gpg: Prepare some key cleaning function for use with secret key packets.
[gnupg.git] / g10 / pkclist.c
index 8efa954..288affc 100644 (file)
@@ -15,7 +15,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>
@@ -428,7 +428,7 @@ do_we_trust( PKT_public_key *pk, unsigned int trustlevel )
     default:
       log_error ("invalid trustlevel %u returned from validation layer\n",
                 trustlevel);
-      /* fall thru */
+      /* fall through */
     case TRUST_UNKNOWN:
     case TRUST_UNDEFINED:
       log_info(_("%s: There is no assurance this key belongs"
@@ -449,6 +449,13 @@ do_we_trust( PKT_public_key *pk, unsigned int trustlevel )
       if( opt.verbose )
        log_info(_("This key belongs to us\n"));
       return 1; /* yes */
+
+    case TRUST_NEVER:
+      /* This can be returned by TOFU, which can return negative
+         assertions.  */
+      log_info(_("%s: This key is bad!  It has been marked as untrusted!\n"),
+               keystr_from_pk(pk));
+      return 0; /* no */
     }
 
   return 1; /*NOTREACHED*/
@@ -472,10 +479,16 @@ do_we_trust_pre( PKT_public_key *pk, unsigned int trustlevel )
       print_fingerprint (NULL, pk, 2);
       tty_printf("\n");
 
-      tty_printf(
-              _("It is NOT certain that the key belongs to the person named\n"
-                "in the user ID.  If you *really* know what you are doing,\n"
-                "you may answer the next question with yes.\n"));
+      if ((trustlevel & TRUST_MASK) == TRUST_NEVER)
+        tty_printf(
+          _("This key is bad!  It has been marked as untrusted!  If you\n"
+            "*really* know what you are doing, you may answer the next\n"
+            "question with yes.\n"));
+      else
+        tty_printf(
+          _("It is NOT certain that the key belongs to the person named\n"
+            "in the user ID.  If you *really* know what you are doing,\n"
+            "you may answer the next question with yes.\n"));
 
       tty_printf("\n");
 
@@ -508,6 +521,9 @@ do_we_trust_pre( PKT_public_key *pk, unsigned int trustlevel )
 static void
 write_trust_status (int statuscode, int trustlevel)
 {
+#ifdef NO_TRUST_MODELS
+  write_status (statuscode);
+#else /* NO_TRUST_MODELS */
   int tm;
 
   /* For the combined tofu+pgp method, we return the trust model which
@@ -517,6 +533,7 @@ write_trust_status (int statuscode, int trustlevel)
   else
     tm = opt.trust_model;
   write_status_strings (statuscode, "0 ", trust_model_string (tm), NULL);
+#endif /* NO_TRUST_MODELS */
 }
 
 
@@ -552,7 +569,7 @@ check_signatures_trust (ctrl_t ctrl, PKT_signature *sig)
     log_info(_("WARNING: this key might be revoked (revocation key"
               " not present)\n"));
 
-  trustlevel = get_validity (ctrl, pk, NULL, sig, 1);
+  trustlevel = get_validity (ctrl, NULL, pk, NULL, sig, 1);
 
   if ( (trustlevel & TRUST_FLAG_REVOKED) )
     {
@@ -638,7 +655,7 @@ check_signatures_trust (ctrl_t ctrl, PKT_signature *sig)
     default:
       log_error ("invalid trustlevel %u returned from validation layer\n",
                  trustlevel);
-      /* fall thru */
+      /* fall through */
     case TRUST_UNKNOWN:
     case TRUST_UNDEFINED:
       write_trust_status (STATUS_TRUST_UNDEFINED, trustlevel);
@@ -650,7 +667,8 @@ check_signatures_trust (ctrl_t ctrl, PKT_signature *sig)
       break;
 
     case TRUST_NEVER:
-      /* currently we won't get that status */
+      /* This level can be returned by TOFU, which supports negative
+       * assertions.  */
       write_trust_status (STATUS_TRUST_NEVER, trustlevel);
       log_info(_("WARNING: We do NOT trust this key!\n"));
       log_info(_("         The signature is probably a FORGERY.\n"));
@@ -775,14 +793,16 @@ expand_id(const char *id,strlist_t *into,unsigned int flags)
 }
 
 /* For simplicity, and to avoid potential loops, we only expand once -
  you can't make an alias that points to an alias. */
* you can't make an alias that points to an alias.  */
 static strlist_t
-expand_group(strlist_t input)
+expand_group (strlist_t input)
 {
-  strlist_t sl,output=NULL,rover;
+  strlist_t output = NULL;
+  strlist_t sl, rover;
 
-  for(rover=input;rover;rover=rover->next)
-    if(expand_id(rover->d,&output,rover->flags)==0)
+  for (rover = input; rover; rover = rover->next)
+    if (!(rover->flags & PK_LIST_FROM_FILE)
+        && !expand_id(rover->d,&output,rover->flags))
       {
        /* Didn't find any groups, so use the existing string */
        sl=add_to_strlist(&output,rover->d);
@@ -794,17 +814,18 @@ expand_group(strlist_t input)
 
 
 /* Helper for build_pk_list to find and check one key.  This helper is
-   also used directly in server mode by the RECIPIENTS command.  On
-   success the new key is added to PK_LIST_ADDR.  NAME is the user id
-   of the key. USE the requested usage and a set MARK_HIDDEN will mark
-   the key in the updated list as a hidden recipient. */
+ * also used directly in server mode by the RECIPIENTS command.  On
+ * success the new key is added to PK_LIST_ADDR.  NAME is the user id
+ * of the key.  USE the requested usage and a set MARK_HIDDEN will
+ * mark the key in the updated list as a hidden recipient.  If
+ * FROM_FILE is true, NAME is is not a user ID but the name of a file
+ * holding a key. */
 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)
+                    int mark_hidden, int from_file, pk_list_t *pk_list_addr)
 {
   int rc;
   PKT_public_key *pk;
-  int trustlevel;
 
   if (!name || !*name)
     return gpg_error (GPG_ERR_INV_USER_ID);
@@ -814,7 +835,10 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
     return gpg_error_from_syserror ();
   pk->req_usage = use;
 
-  rc = get_pubkey_byname (ctrl, NULL, pk, name, NULL, NULL, 0, 0);
+  if (from_file)
+    rc = get_pubkey_fromfile (ctrl, pk, name);
+  else
+    rc = get_best_pubkey_byname (ctrl, NULL, pk, name, NULL, 0, 0);
   if (rc)
     {
       int code;
@@ -844,24 +868,28 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
     }
 
   /* Key found and usable.  Check validity. */
-  trustlevel = get_validity (ctrl, pk, pk->user_id, NULL, 1);
-  if ( (trustlevel & TRUST_FLAG_DISABLED) )
+  if (!from_file)
     {
-      /* Key has been disabled. */
-      send_status_inv_recp (13, name);
-      log_info (_("%s: skipped: public key is disabled\n"), name);
-      free_public_key (pk);
-      return GPG_ERR_UNUSABLE_PUBKEY;
-    }
+      int trustlevel;
 
-  if ( !do_we_trust_pre (pk, trustlevel) )
-    {
-      /* We don't trust this key.  */
-      send_status_inv_recp (10, name);
-      free_public_key (pk);
-      return GPG_ERR_UNUSABLE_PUBKEY;
+      trustlevel = get_validity (ctrl, NULL, pk, pk->user_id, NULL, 1);
+      if ( (trustlevel & TRUST_FLAG_DISABLED) )
+        {
+          /* Key has been disabled. */
+          send_status_inv_recp (13, name);
+          log_info (_("%s: skipped: public key is disabled\n"), name);
+          free_public_key (pk);
+          return GPG_ERR_UNUSABLE_PUBKEY;
+        }
+
+      if ( !do_we_trust_pre (pk, trustlevel) )
+        {
+          /* We don't trust this key.  */
+          send_status_inv_recp (10, name);
+          free_public_key (pk);
+          return GPG_ERR_UNUSABLE_PUBKEY;
+        }
     }
-  /* Note: do_we_trust may have changed the trustlevel. */
 
   /* Skip the actual key if the key is already present in the
      list.  */
@@ -894,22 +922,24 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
 
 
 /* This is the central function to collect the keys for recipients.
-   It is thus used to prepare a public key encryption. encrypt-to
-   keys, default keys and the keys for the actual recipients are all
-   collected here.  When not in batch mode and no recipient has been
-   passed on the commandline, the function will also ask for
-   recipients.
-
-   RCPTS is a string list with the recipients; NULL is an allowed
-   value but not very useful.  Group expansion is done on these names;
-   they may be in any of the user Id formats we can handle.  The flags
-   bits for each string in the string list are used for:
-     Bit 0 (PK_LIST_ENCRYPT_TO): This is an encrypt-to recipient.
-     Bit 1 (PK_LIST_HIDDEN)    : This is a hidden recipient.
-
-   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.
+ * It is thus used to prepare a public key encryption. encrypt-to
+ * keys, default keys and the keys for the actual recipients are all
+ * collected here.  When not in batch mode and no recipient has been
+ * passed on the commandline, the function will also ask for
+ * recipients.
+ *
+ * RCPTS is a string list with the recipients; NULL is an allowed
+ * value but not very useful.  Group expansion is done on these names;
+ * they may be in any of the user Id formats we can handle.  The flags
+ * bits for each string in the string list are used for:
+ *
+ * - PK_LIST_ENCRYPT_TO :: This is an encrypt-to recipient.
+ * - PK_LIST_HIDDEN     :: This is a hidden recipient.
+ * - PK_LIST_FROM_FILE  :: The argument is a file with a key.
+ *
+ * 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)
@@ -1182,7 +1212,8 @@ build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list)
                 { /* Check validity of this key. */
                   int trustlevel;
 
-                  trustlevel = get_validity (ctrl, pk, pk->user_id, NULL, 1);
+                  trustlevel =
+                    get_validity (ctrl, NULL, pk, pk->user_id, NULL, 1);
                   if ( (trustlevel & TRUST_FLAG_DISABLED) )
                     {
                       tty_printf (_("Public key is disabled.\n") );
@@ -1269,6 +1300,7 @@ build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list)
 
           rc = find_and_check_key (ctrl, remusr->d, PUBKEY_USAGE_ENC,
                                    !!(remusr->flags&PK_LIST_HIDDEN),
+                                   !!(remusr->flags&PK_LIST_FROM_FILE),
                                    &pk_list);
           if (rc)
             goto fail;
@@ -1283,6 +1315,29 @@ build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list)
       rc = GPG_ERR_NO_USER_ID;
     }
 
+#ifdef USE_TOFU
+  if (! rc && (opt.trust_model == TM_TOFU_PGP || opt.trust_model == TM_TOFU))
+    {
+      PK_LIST iter;
+      for (iter = pk_list; iter; iter = iter->next)
+        {
+          int rc2;
+
+          /* Note: we already resolved any conflict when looking up
+             the key.  Don't annoy the user again if she selected
+             accept once.  */
+          rc2 = tofu_register_encryption (ctrl, iter->pk, NULL, 0);
+          if (rc2)
+            log_info ("WARNING: Failed to register encryption to %s"
+                      " with TOFU engine\n",
+                      keystr (pk_main_keyid (iter->pk)));
+          else if (DBG_TRUST)
+            log_debug ("Registered encryption to %s with TOFU DB.\n",
+                      keystr (pk_main_keyid (iter->pk)));
+        }
+    }
+#endif /*USE_TOFU*/
+
  fail:
 
   if ( rc )