gpg: Keep a lock during the read-update/insert cycle in import.
[gnupg.git] / g10 / trust.c
index 8790754..ee6078b 100644 (file)
@@ -16,7 +16,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 
 #include "gpg.h"
 #include "keydb.h"
-#include "util.h"
+#include "../common/util.h"
 #include "options.h"
 #include "packet.h"
 #include "main.h"
-#include "i18n.h"
+#include "../common/i18n.h"
 #include "trustdb.h"
-#include "host2net.h"
+#include "../common/host2net.h"
 
 
 /* Return true if key is disabled.  Note that this is usually used via
    the pk_is_disabled macro.  */
 int
-cache_disabled_value (PKT_public_key *pk)
+cache_disabled_value (ctrl_t ctrl, PKT_public_key *pk)
 {
 #ifdef NO_TRUST_MODELS
   (void)pk;
   return 0;
 #else
-  return tdb_cache_disabled_value (pk);
+  return tdb_cache_disabled_value (ctrl, pk);
 #endif
 }
 
@@ -145,13 +145,13 @@ uid_trust_string_fixed (ctrl_t ctrl, PKT_public_key *key, PKT_user_id *uid)
          uid are both NULL, or neither are NULL. */
       return _("10 translator see trust.c:uid_trust_string_fixed");
     }
-  else if(uid->is_revoked || (key && key->flags.revoked))
+  else if(uid->flags.revoked || (key && key->flags.revoked))
     return                         _("[ revoked]");
-  else if(uid->is_expired)
+  else if(uid->flags.expired)
     return                         _("[ expired]");
   else if(key)
     {
-      switch (get_validity (ctrl, key, uid, NULL, 0) & TRUST_MASK)
+      switch (get_validity (ctrl, NULL, key, uid, NULL, 0) & TRUST_MASK)
         {
         case TRUST_UNKNOWN:   return _("[ unknown]");
         case TRUST_EXPIRED:   return _("[ expired]");
@@ -173,23 +173,24 @@ uid_trust_string_fixed (ctrl_t ctrl, PKT_public_key *key, PKT_user_id *uid)
  * The key should be the primary key.
  */
 unsigned int
-get_ownertrust (PKT_public_key *pk)
+get_ownertrust (ctrl_t ctrl, PKT_public_key *pk)
 {
 #ifdef NO_TRUST_MODELS
   (void)pk;
   return TRUST_UNKNOWN;
 #else
-  return tdb_get_ownertrust (pk);
+  return tdb_get_ownertrust (ctrl, pk, 0);
 #endif
 }
 
 
 /*
  * Same as get_ownertrust but this takes the minimum ownertrust value
- * into into account, and will bump up the value as needed.
+ * into account, and will bump up the value as needed.  NO_CREATE
+ * inhibits creation of a trustdb it that does not yet exists.
  */
 static int
-get_ownertrust_with_min (PKT_public_key *pk)
+get_ownertrust_with_min (ctrl_t ctrl, PKT_public_key *pk, int no_create)
 {
 #ifdef NO_TRUST_MODELS
   (void)pk;
@@ -197,8 +198,15 @@ get_ownertrust_with_min (PKT_public_key *pk)
 #else
   unsigned int otrust, otrust_min;
 
-  otrust = (tdb_get_ownertrust (pk) & TRUST_MASK);
-  otrust_min = tdb_get_min_ownertrust (pk);
+  /* Shortcut instead of doing the same twice in the two tdb_get
+   * functions: If the caller asked not to create a trustdb we call
+   * init_trustdb directly and allow it to fail with an error code for
+   * a non-existing trustdb.  */
+  if (no_create && init_trustdb (ctrl, 1))
+    return TRUST_UNKNOWN;
+
+  otrust = (tdb_get_ownertrust (ctrl, pk, no_create) & TRUST_MASK);
+  otrust_min = tdb_get_min_ownertrust (ctrl, pk, no_create);
   if (otrust < otrust_min)
     {
       /* If the trust that the user has set is less than the trust
@@ -217,23 +225,25 @@ get_ownertrust_with_min (PKT_public_key *pk)
 
 /*
  * Same as get_ownertrust but return a trust letter instead of an
- * value.  This takes the minimum ownertrust value into account.
+ * value.  This takes the minimum ownertrust value into account.  If
+ * NO_CREATE is set, no efforts for creating a trustdb will be taken.
  */
 int
-get_ownertrust_info (PKT_public_key *pk)
+get_ownertrust_info (ctrl_t ctrl, PKT_public_key *pk, int no_create)
 {
-  return trust_letter (get_ownertrust_with_min (pk));
+  return trust_letter (get_ownertrust_with_min (ctrl, pk, no_create));
 }
 
 
 /*
  * Same as get_ownertrust but return a trust string instead of an
- * value.  This takes the minimum ownertrust value into account.
+ * value.  This takes the minimum ownertrust value into account.  If
+ * NO_CREATE is set, no efforts for creating a trustdb will be taken.
  */
 const char *
-get_ownertrust_string (PKT_public_key *pk)
+get_ownertrust_string (ctrl_t ctrl, PKT_public_key *pk, int no_create)
 {
-  return trust_value_to_string (get_ownertrust_with_min (pk));
+  return trust_value_to_string (get_ownertrust_with_min (ctrl, pk, no_create));
 }
 
 
@@ -242,34 +252,34 @@ get_ownertrust_string (PKT_public_key *pk)
  * The key should be a primary one.
  */
 void
-update_ownertrust (PKT_public_key *pk, unsigned int new_trust)
+update_ownertrust (ctrl_t ctrl, PKT_public_key *pk, unsigned int new_trust)
 {
 #ifdef NO_TRUST_MODELS
   (void)pk;
   (void)new_trust;
 #else
-  tdb_update_ownertrust (pk, new_trust);
+  tdb_update_ownertrust (ctrl, pk, new_trust);
 #endif
 }
 
 
 int
-clear_ownertrusts (PKT_public_key *pk)
+clear_ownertrusts (ctrl_t ctrl, PKT_public_key *pk)
 {
 #ifdef NO_TRUST_MODELS
   (void)pk;
   return 0;
 #else
-  return tdb_clear_ownertrusts (pk);
+  return tdb_clear_ownertrusts (ctrl, pk);
 #endif
 }
 
 
 void
-revalidation_mark (void)
+revalidation_mark (ctrl_t ctrl)
 {
 #ifndef NO_TRUST_MODELS
-  tdb_revalidation_mark ();
+  tdb_revalidation_mark (ctrl);
 #endif
 }
 
@@ -297,12 +307,13 @@ check_or_update_trustdb (ctrl_t ctrl)
 
 
 /*
- * Return the validity information for PK.  If the namehash is not
- * NULL, the validity of the corresponding user ID is returned,
- * otherwise, a reasonable value for the entire key is returned.
+ * Return the validity information for KB/PK (at least one must be
+ * non-NULL).  If the namehash is not NULL, the validity of the
+ * corresponding user ID is returned, otherwise, a reasonable value
+ * for the entire key is returned.
  */
 unsigned int
-get_validity (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid,
+get_validity (ctrl_t ctrl, kbnode_t kb, PKT_public_key *pk, PKT_user_id *uid,
               PKT_signature *sig, int may_ask)
 {
   int rc;
@@ -310,6 +321,16 @@ get_validity (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid,
   u32 kid[2];
   PKT_public_key *main_pk;
 
+  if (kb && pk)
+    log_assert (keyid_cmp (pk_main_keyid (pk),
+                           pk_main_keyid (kb->pkt->pkt.public_key)) == 0);
+
+  if (! pk)
+    {
+      log_assert (kb);
+      pk = kb->pkt->pkt.public_key;
+    }
+
   if (uid)
     namehash_from_uid (uid);
 
@@ -317,17 +338,22 @@ get_validity (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid,
   if (pk->main_keyid[0] != kid[0] || pk->main_keyid[1] != kid[1])
     {
       /* This is a subkey - get the mainkey. */
-      main_pk = xmalloc_clear (sizeof *main_pk);
-      rc = get_pubkey (main_pk, pk->main_keyid);
-      if (rc)
+      if (kb)
+        main_pk = kb->pkt->pkt.public_key;
+      else
         {
-         char *tempkeystr = xstrdup (keystr (pk->main_keyid));
-          log_error ("error getting main key %s of subkey %s: %s\n",
-                     tempkeystr, keystr (kid), gpg_strerror (rc));
-         xfree (tempkeystr);
-          validity = TRUST_UNKNOWN;
-          goto leave;
-       }
+          main_pk = xmalloc_clear (sizeof *main_pk);
+          rc = get_pubkey (ctrl, main_pk, pk->main_keyid);
+          if (rc)
+            {
+              char *tempkeystr = xstrdup (keystr (pk->main_keyid));
+              log_error ("error getting main key %s of subkey %s: %s\n",
+                         tempkeystr, keystr (kid), gpg_strerror (rc));
+              xfree (tempkeystr);
+              validity = TRUST_UNKNOWN;
+              goto leave;
+            }
+        }
     }
   else
     main_pk = pk;
@@ -335,7 +361,7 @@ get_validity (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid,
 #ifdef NO_TRUST_MODELS
   validity = TRUST_UNKNOWN;
 #else
-  validity = tdb_get_validity_core (ctrl, pk, uid, main_pk, sig, may_ask);
+  validity = tdb_get_validity_core (ctrl, kb, pk, uid, main_pk, sig, may_ask);
 #endif
 
  leave:
@@ -350,21 +376,28 @@ get_validity (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid,
     validity = ((validity & (~TRUST_MASK | TRUST_FLAG_PENDING_CHECK))
                 | TRUST_EXPIRED);
 
-  if (main_pk != pk)
+  if (main_pk != pk && !kb)
     free_public_key (main_pk);
   return validity;
 }
 
 
 int
-get_validity_info (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid)
+get_validity_info (ctrl_t ctrl, kbnode_t kb, PKT_public_key *pk,
+                   PKT_user_id *uid)
 {
   int trustlevel;
 
+  if (kb && pk)
+    log_assert (keyid_cmp (pk_main_keyid (pk),
+                           pk_main_keyid (kb->pkt->pkt.public_key)) == 0);
+
+  if (! pk && kb)
+    pk = kb->pkt->pkt.public_key;
   if (!pk)
     return '?';  /* Just in case a NULL PK is passed.  */
 
-  trustlevel = get_validity (ctrl, pk, uid, NULL, 0);
+  trustlevel = get_validity (ctrl, kb, pk, uid, NULL, 0);
   if ((trustlevel & TRUST_FLAG_REVOKED))
     return 'r';
   return trust_letter (trustlevel);
@@ -379,7 +412,7 @@ get_validity_string (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid)
   if (!pk)
     return "err";  /* Just in case a NULL PK is passed.  */
 
-  trustlevel = get_validity (ctrl, pk, uid, NULL, 0);
+  trustlevel = get_validity (ctrl, NULL, pk, uid, NULL, 0);
   if ((trustlevel & TRUST_FLAG_REVOKED))
     return _("revoked");
   return trust_value_to_string (trustlevel);
@@ -397,7 +430,7 @@ get_validity_string (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid)
  * 9 and 10 are used for internal purposes.
  */
 void
-mark_usable_uid_certs (kbnode_t keyblock, kbnode_t uidnode,
+mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
                        u32 *main_kid, struct key_item *klist,
                        u32 curtime, u32 *next_expire)
 {
@@ -411,7 +444,8 @@ mark_usable_uid_certs (kbnode_t keyblock, kbnode_t uidnode,
 
       node->flag &= ~(1<<8 | 1<<9 | 1<<10 | 1<<11 | 1<<12);
       if (node->pkt->pkttype == PKT_USER_ID
-          || node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+          || node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+          || node->pkt->pkttype == PKT_SECRET_SUBKEY)
         break; /* ready */
       if (node->pkt->pkttype != PKT_SIGNATURE)
         continue;
@@ -427,7 +461,7 @@ mark_usable_uid_certs (kbnode_t keyblock, kbnode_t uidnode,
                     invalid signature */
       if (klist && !is_in_klist (klist, sig))
         continue;  /* no need to check it then */
-      if ((rc=check_key_signature (keyblock, node, NULL)))
+      if ((rc=check_key_signature (ctrl, keyblock, node, NULL)))
        {
          /* we ignore anything that won't verify, but tag the
             no_pubkey case */
@@ -453,7 +487,8 @@ mark_usable_uid_certs (kbnode_t keyblock, kbnode_t uidnode,
       u32 kid[2];
       u32 sigdate;
 
-      if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+      if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+          || node->pkt->pkttype == PKT_SECRET_SUBKEY)
         break;
       if ( !(node->flag & (1<<9)) )
         continue; /* not a node to look at */
@@ -468,7 +503,8 @@ mark_usable_uid_certs (kbnode_t keyblock, kbnode_t uidnode,
       /* Now find the latest and greatest signature */
       for (n=uidnode->next; n; n = n->next)
         {
-          if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+          if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY
+              || n->pkt->pkttype == PKT_SECRET_SUBKEY)
             break;
           if ( !(n->flag & (1<<9)) )
             continue;
@@ -558,21 +594,22 @@ mark_usable_uid_certs (kbnode_t keyblock, kbnode_t uidnode,
 
 
 static int
-clean_sigs_from_uid (kbnode_t keyblock, kbnode_t uidnode,
+clean_sigs_from_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
                      int noisy, int self_only)
 {
   int deleted = 0;
   kbnode_t node;
   u32 keyid[2];
 
-  log_assert (keyblock->pkt->pkttype==PKT_PUBLIC_KEY);
+  log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
+              || keyblock->pkt->pkttype == PKT_SECRET_KEY);
 
   keyid_from_pk (keyblock->pkt->pkt.public_key, keyid);
 
   /* Passing in a 0 for current time here means that we'll never weed
      out an expired sig.  This is correct behavior since we want to
      keep the most recent expired sig in a series. */
-  mark_usable_uid_certs (keyblock, uidnode, NULL, NULL, 0, NULL);
+  mark_usable_uid_certs (ctrl, keyblock, uidnode, NULL, NULL, 0, NULL);
 
   /* What we want to do here is remove signatures that are not
      considered as part of the trust calculations.  Thus, all invalid
@@ -658,14 +695,15 @@ clean_uid_from_key (kbnode_t keyblock, kbnode_t uidnode, int noisy)
   PKT_user_id *uid = uidnode->pkt->pkt.user_id;
   int deleted = 0;
 
-  log_assert (keyblock->pkt->pkttype==PKT_PUBLIC_KEY);
+  log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
+              || keyblock->pkt->pkttype == PKT_SECRET_KEY);
   log_assert (uidnode->pkt->pkttype==PKT_USER_ID);
 
   /* Skip valid user IDs, compacted user IDs, and non-self-signed user
      IDs if --allow-non-selfsigned-uid is set. */
   if (uid->created
       || uid->flags.compacted
-      || (!uid->is_expired && !uid->is_revoked && opt.allow_non_selfsigned_uid))
+      || (!uid->flags.expired && !uid->flags.revoked && opt.allow_non_selfsigned_uid))
     return 0;
 
   for (node=uidnode->next;
@@ -685,9 +723,9 @@ clean_uid_from_key (kbnode_t keyblock, kbnode_t uidnode, int noisy)
       const char *reason;
       char *user = utf8_to_native (uid->name, uid->len, 0);
 
-      if (uid->is_revoked)
+      if (uid->flags.revoked)
        reason = _("revoked");
-      else if (uid->is_expired)
+      else if (uid->flags.expired)
        reason = _("expired");
       else
        reason = _("invalid");
@@ -705,12 +743,13 @@ clean_uid_from_key (kbnode_t keyblock, kbnode_t uidnode, int noisy)
 
 /* Needs to be called after a merge_keys_and_selfsig() */
 void
-clean_one_uid (kbnode_t keyblock, kbnode_t uidnode, int noisy, int self_only,
-               int *uids_cleaned, int *sigs_cleaned)
+clean_one_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
+               int noisy, int self_only, int *uids_cleaned, int *sigs_cleaned)
 {
   int dummy = 0;
 
-  log_assert (keyblock->pkt->pkttype==PKT_PUBLIC_KEY);
+  log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
+              || keyblock->pkt->pkttype == PKT_SECRET_KEY);
   log_assert (uidnode->pkt->pkttype==PKT_USER_ID);
 
   if (!uids_cleaned)
@@ -723,24 +762,46 @@ clean_one_uid (kbnode_t keyblock, kbnode_t uidnode, int noisy, int self_only,
      to bother with the other.  */
   *uids_cleaned += clean_uid_from_key (keyblock, uidnode, noisy);
   if (!uidnode->pkt->pkt.user_id->flags.compacted)
-    *sigs_cleaned += clean_sigs_from_uid (keyblock, uidnode, noisy, self_only);
+    *sigs_cleaned += clean_sigs_from_uid (ctrl, keyblock, uidnode,
+                                          noisy, self_only);
 }
 
 
+/* NB: This function marks the deleted nodes only and the caller is
+ * responsible to skip or remove them.  */
 void
-clean_key (kbnode_t keyblock, int noisy, int self_only,
+clean_key (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only,
            int *uids_cleaned, int *sigs_cleaned)
 {
-  kbnode_t uidnode;
+  kbnode_t node;
 
-  merge_keys_and_selfsig (keyblock);
+  merge_keys_and_selfsig (ctrl, keyblock);
 
-  for (uidnode = keyblock->next;
-       uidnode && uidnode->pkt->pkttype != PKT_PUBLIC_SUBKEY;
-       uidnode = uidnode->next)
+  for (node = keyblock->next;
+       node && !(node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+                    || node->pkt->pkttype == PKT_SECRET_SUBKEY);
+       node = node->next)
     {
-      if (uidnode->pkt->pkttype == PKT_USER_ID)
-        clean_one_uid (keyblock, uidnode,noisy, self_only,
+      if (node->pkt->pkttype == PKT_USER_ID)
+        clean_one_uid (ctrl, keyblock, node, noisy, self_only,
                        uids_cleaned, sigs_cleaned);
     }
+
+  /* Remove bogus subkey binding signatures: The only signatures
+   * allowed are of class 0x18 and 0x28.  */
+  log_assert (!node || (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+                        || node->pkt->pkttype == PKT_SECRET_SUBKEY));
+  for (; node; node = node->next)
+    {
+      if (is_deleted_kbnode (node))
+        continue;
+      if (node->pkt->pkttype == PKT_SIGNATURE
+          && !(IS_SUBKEY_SIG (node->pkt->pkt.signature)
+                || IS_SUBKEY_REV (node->pkt->pkt.signature)))
+        {
+          delete_kbnode (node);
+          if (sigs_cleaned)
+            ++*sigs_cleaned;
+        }
+    }
 }