agent,w32: Fix annoying output to DebugView.
[gnupg.git] / g10 / pkclist.c
index f76c186..288affc 100644 (file)
@@ -1,6 +1,6 @@
 /* pkclist.c - create a list of public keys
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
- *               2008, 2009 Free Software Foundation, Inc.
+ *               2008, 2009, 2010 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -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>
@@ -23,7 +23,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "options.h"
@@ -37,6 +36,7 @@
 #include "status.h"
 #include "photoid.h"
 #include "i18n.h"
+#include "tofu.h"
 
 #define CONTROL_D ('D' - 'A' + 1)
 
@@ -47,7 +47,7 @@ send_status_inv_recp (int reason, const char *name)
 
   snprintf (buf, sizeof buf, "%d ", reason);
   write_status_text_and_buffer (STATUS_INV_RECP, buf,
-                                name, strlen (name), 
+                                name, strlen (name),
                                 -1);
 }
 
@@ -112,7 +112,7 @@ do_show_revocation_reason( PKT_signature *sig )
 void
 show_revocation_reason( PKT_public_key *pk, int mode )
 {
-    /* Hmmm, this is not so easy becuase we have to duplicate the code
+    /* Hmmm, this is not so easy because we have to duplicate the code
      * used in the trustbd to calculate the keyflags.  We need to find
      * a clean way to check revocation certificates on keys and
      * signatures.  And there should be no duplicate code.  Because we
@@ -127,7 +127,7 @@ show_revocation_reason( PKT_public_key *pk, int mode )
 
     /* get the keyblock */
     fingerprint_from_pk( pk, fingerprint, &fingerlen );
-    rc = get_keyblock_byfprint( &keyblock, fingerprint, fingerlen );
+    rc = get_pubkey_byfprint(NULL, &keyblock, fingerprint, fingerlen);
     if( rc ) { /* that should never happen */
        log_debug( "failed to get the keyblock\n");
        return;
@@ -170,14 +170,15 @@ show_revocation_reason( PKT_public_key *pk, int mode )
  * mode: 0 = standard
  *       1 = Without key info and additional menu option 'm'
  *           this does also add an option to set the key to ultimately trusted.
- * Returns: 
+ * Returns:
  *      -2 = nothing changed - caller should show some additional info
  *      -1 = quit operation
  *       0 = nothing changed
  *       1 = new ownertrust now in new_trust
  */
+#ifndef NO_TRUST_MODELS
 static int
-do_edit_ownertrust (PKT_public_key *pk, int mode,
+do_edit_ownertrust (ctrl_t ctrl, PKT_public_key *pk, int mode,
                     unsigned *new_trust, int defer_help )
 {
   char *p;
@@ -187,7 +188,7 @@ do_edit_ownertrust (PKT_public_key *pk, int mode,
   int show=0;
   int min_num;
   int did_help=defer_help;
-  unsigned int minimum=get_min_ownertrust(pk);
+  unsigned int minimum = tdb_get_min_ownertrust (pk);
 
   switch(minimum)
     {
@@ -202,11 +203,11 @@ do_edit_ownertrust (PKT_public_key *pk, int mode,
   for(;;) {
     /* A string with valid answers.
 
-       Note to translators: These are the allowed answers in lower and
+       TRANSLATORS: These are the allowed answers in lower and
        uppercase.  Below you will find the matching strings which
        should be translated accordingly and the letter changed to
        match the one in the answer string.
-    
+
          i = please show me more information
          m = back to the main menu
          s = skip this key
@@ -214,19 +215,18 @@ do_edit_ownertrust (PKT_public_key *pk, int mode,
     */
     const char *ans = _("iImMqQsS");
 
-    if( !did_help ) 
+    if( !did_help )
       {
-        if( !mode ) 
+        if( !mode )
           {
             KBNODE keyblock, un;
 
-            tty_printf(_("No trust value assigned to:\n"));
-           tty_printf("%4u%c/%s %s\n",nbits_from_pk( pk ),
-                      pubkey_letter( pk->pubkey_algo ),
-                       keystr(keyid), datestr_from_pk( pk ) );
-           p=get_user_id_native(keyid);
-           tty_printf(_("      \"%s\"\n"),p);
-           xfree(p);
+            tty_printf (_("No trust value assigned to:\n"));
+            print_key_line (NULL, pk, 0);
+
+           p = get_user_id_native(keyid);
+           tty_printf (_("      \"%s\"\n"),p);
+           xfree (p);
 
             keyblock = get_pubkeyblock (keyid);
             if (!keyblock)
@@ -243,10 +243,11 @@ do_edit_ownertrust (PKT_public_key *pk, int mode,
                 if (un->pkt->pkt.user_id->is_primary
                    && !un->pkt->pkt.user_id->attrib_data )
                  continue;
-                
+
                if((opt.verify_options&VERIFY_SHOW_PHOTOS)
                   && un->pkt->pkt.user_id->attrib_data)
-                 show_photos (un->pkt->pkt.user_id->attribs,
+                 show_photos (ctrl,
+                               un->pkt->pkt.user_id->attribs,
                                un->pkt->pkt.user_id->numattribs, pk,
                                un->pkt->pkt.user_id);
 
@@ -255,8 +256,8 @@ do_edit_ownertrust (PKT_public_key *pk, int mode,
 
                tty_printf(_("  aka \"%s\"\n"),p);
              }
-        
-            print_fingerprint (pk, 2);
+
+            print_fingerprint (NULL, pk, 2);
             tty_printf("\n");
            release_kbnode (keyblock);
           }
@@ -313,7 +314,7 @@ do_edit_ownertrust (PKT_public_key *pk, int mode,
       did_help = 0;
     else if( *p && p[1] )
       ;
-    else if( !p[1] && ((*p >= '0'+min_num) && *p <= (mode?'5':'4')) ) 
+    else if( !p[1] && ((*p >= '0'+min_num) && *p <= (mode?'5':'4')) )
       {
         unsigned int trust;
         switch( *p )
@@ -339,14 +340,14 @@ do_edit_ownertrust (PKT_public_key *pk, int mode,
       }
 #if 0
     /* not yet implemented */
-    else if( *p == ans[0] || *p == ans[1] ) 
+    else if( *p == ans[0] || *p == ans[1] )
       {
         tty_printf(_("Certificates leading to an ultimately trusted key:\n"));
         show = 1;
         break;
       }
 #endif
-    else if( mode && (*p == ans[2] || *p == ans[3] || *p == CONTROL_D ) ) 
+    else if( mode && (*p == ans[2] || *p == ans[3] || *p == CONTROL_D ) )
       {
         break ; /* back to the menu */
       }
@@ -364,21 +365,24 @@ do_edit_ownertrust (PKT_public_key *pk, int mode,
   xfree(p);
   return show? -2: quit? -1 : changed;
 }
+#endif /*!NO_TRUST_MODELS*/
+
 
-/* 
+/*
  * Display a menu to change the ownertrust of the key PK (which should
- * be a primary key).  
+ * be a primary key).
  * For mode values see do_edit_ownertrust ()
  */
+#ifndef NO_TRUST_MODELS
 int
-edit_ownertrust (PKT_public_key *pk, int mode )
+edit_ownertrust (ctrl_t ctrl, PKT_public_key *pk, int mode )
 {
   unsigned int trust = 0;
   int no_help = 0;
 
   for(;;)
     {
-      switch ( do_edit_ownertrust (pk, mode, &trust, no_help ) )
+      switch ( do_edit_ownertrust (ctrl, pk, mode, &trust, no_help ) )
         {
         case -1: /* quit */
           return -1;
@@ -395,6 +399,7 @@ edit_ownertrust (PKT_public_key *pk, int mode )
         }
     }
 }
+#endif /*!NO_TRUST_MODELS*/
 
 
 /****************
@@ -414,7 +419,7 @@ do_we_trust( PKT_public_key *pk, unsigned int trustlevel )
   if( opt.trust_model==TM_ALWAYS )
     {
       if( opt.verbose )
-       log_info("No trust check due to `--trust-model always' option\n");
+       log_info("No trust check due to '--trust-model always' option\n");
       return 1;
     }
 
@@ -423,8 +428,8 @@ do_we_trust( PKT_public_key *pk, unsigned int trustlevel )
     default:
       log_error ("invalid trustlevel %u returned from validation layer\n",
                 trustlevel);
-      /* fall thru */
-    case TRUST_UNKNOWN: 
+      /* fall through */
+    case TRUST_UNKNOWN:
     case TRUST_UNDEFINED:
       log_info(_("%s: There is no assurance this key belongs"
                 " to the named user\n"),keystr_from_pk(pk));
@@ -444,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*/
@@ -464,22 +476,28 @@ do_we_trust_pre( PKT_public_key *pk, unsigned int trustlevel )
   if( !opt.batch && !rc )
     {
       print_pubkey_info(NULL,pk);
-      print_fingerprint (pk, 2);
+      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");
 
-      
+
       if (is_status_enabled ())
         {
           u32 kid[2];
           char *hint_str;
-          
+
           keyid_from_pk (pk, kid);
           hint_str = get_long_user_id_string ( kid );
           write_status_text ( STATUS_USERID_HINT, hint_str );
@@ -499,22 +517,42 @@ do_we_trust_pre( PKT_public_key *pk, unsigned int trustlevel )
 }
 
 
+/* Write a TRUST_foo status line inclduing the validation model.  */
+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
+   * was responsible for the trustlevel.  */
+  if (opt.trust_model == TM_TOFU_PGP)
+    tm = (trustlevel & TRUST_FLAG_TOFU_BASED)? TM_TOFU : TM_PGP;
+  else
+    tm = opt.trust_model;
+  write_status_strings (statuscode, "0 ", trust_model_string (tm), NULL);
+#endif /* NO_TRUST_MODELS */
+}
+
+
 /****************
  * Check whether we can trust this signature.
- * Returns: Error if we shall not trust this signatures.
+ * Returns an error code if we should not trust this signature.
  */
 int
-check_signatures_trust( PKT_signature *sig )
+check_signatures_trust (ctrl_t ctrl, PKT_signature *sig)
 {
   PKT_public_key *pk = xmalloc_clear( sizeof *pk );
-  unsigned int trustlevel;
+  unsigned int trustlevel = TRUST_UNKNOWN;
   int rc=0;
 
   rc = get_pubkey( pk, sig->keyid );
-  if (rc) 
+  if (rc)
     { /* this should not happen */
       log_error("Ooops; the key vanished  - can't check the trust\n");
-      rc = G10ERR_NO_PUBKEY;
+      rc = GPG_ERR_NO_PUBKEY;
       goto leave;
     }
 
@@ -523,20 +561,20 @@ check_signatures_trust( PKT_signature *sig )
       if( !opt.quiet )
         log_info(_("WARNING: Using untrusted key!\n"));
       if (opt.with_fingerprint)
-        print_fingerprint (pk, 1);
+        print_fingerprint (NULL, pk, 1);
       goto leave;
     }
 
-  if(pk->maybe_revoked && !pk->is_revoked)
+  if(pk->flags.maybe_revoked && !pk->flags.revoked)
     log_info(_("WARNING: this key might be revoked (revocation key"
               " not present)\n"));
 
-  trustlevel = get_validity (pk, NULL);
+  trustlevel = get_validity (ctrl, NULL, pk, NULL, sig, 1);
 
-  if ( (trustlevel & TRUST_FLAG_REVOKED) ) 
+  if ( (trustlevel & TRUST_FLAG_REVOKED) )
     {
       write_status( STATUS_KEYREVOKED );
-      if(pk->is_revoked==2)
+      if(pk->flags.revoked == 2)
        log_info(_("WARNING: This key has been revoked by its"
                   " designated revoker!\n"));
       else
@@ -544,13 +582,13 @@ check_signatures_trust( PKT_signature *sig )
       log_info(_("         This could mean that the signature is forged.\n"));
       show_revocation_reason( pk, 0 );
     }
-  else if ((trustlevel & TRUST_FLAG_SUB_REVOKED) ) 
+  else if ((trustlevel & TRUST_FLAG_SUB_REVOKED) )
     {
       write_status( STATUS_KEYREVOKED );
       log_info(_("WARNING: This subkey has been revoked by its owner!\n"));
       show_revocation_reason( pk, 0 );
     }
-  
+
   if ((trustlevel & TRUST_FLAG_DISABLED))
     log_info (_("Note: This key has been disabled.\n"));
 
@@ -572,20 +610,20 @@ check_signatures_trust( PKT_signature *sig )
         {
           okay = 1;
           write_status_text (STATUS_PKA_TRUST_GOOD, sig->pka_info->email);
-          log_info (_("Note: Verified signer's address is `%s'\n"),
+          log_info (_("Note: Verified signer's address is '%s'\n"),
                     sig->pka_info->email);
         }
       else
         {
           okay = 0;
           write_status_text (STATUS_PKA_TRUST_BAD, sig->pka_info->email);
-          log_info (_("Note: Signer's address `%s' "
+          log_info (_("Note: Signer's address '%s' "
                       "does not match DNS entry\n"), sig->pka_info->email);
         }
 
-      switch ( (trustlevel & TRUST_MASK) ) 
+      switch ( (trustlevel & TRUST_MASK) )
         {
-        case TRUST_UNKNOWN: 
+        case TRUST_UNKNOWN:
         case TRUST_UNDEFINED:
         case TRUST_MARGINAL:
           if (okay && opt.verify_options&VERIFY_PKA_TRUST_INCREASE)
@@ -607,56 +645,57 @@ check_signatures_trust( PKT_signature *sig )
     }
 
   /* Now let the user know what up with the trustlevel. */
-  switch ( (trustlevel & TRUST_MASK) ) 
+  switch ( (trustlevel & TRUST_MASK) )
     {
     case TRUST_EXPIRED:
       log_info(_("Note: This key has expired!\n"));
-      print_fingerprint (pk, 1);
+      print_fingerprint (NULL, pk, 1);
       break;
-        
+
     default:
       log_error ("invalid trustlevel %u returned from validation layer\n",
                  trustlevel);
-      /* fall thru */
-    case TRUST_UNKNOWN: 
+      /* fall through */
+    case TRUST_UNKNOWN:
     case TRUST_UNDEFINED:
-      write_status( STATUS_TRUST_UNDEFINED );
+      write_trust_status (STATUS_TRUST_UNDEFINED, trustlevel);
       log_info(_("WARNING: This key is not certified with"
                  " a trusted signature!\n"));
       log_info(_("         There is no indication that the "
                  "signature belongs to the owner.\n" ));
-      print_fingerprint (pk, 1);
+      print_fingerprint (NULL, pk, 1);
       break;
 
     case TRUST_NEVER:
-      /* currently we won't get that status */
-      write_status( STATUS_TRUST_NEVER );
+      /* 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"));
       if (opt.with_fingerprint)
-        print_fingerprint (pk, 1);
+        print_fingerprint (NULL, pk, 1);
       rc = gpg_error (GPG_ERR_BAD_SIGNATURE);
       break;
 
     case TRUST_MARGINAL:
-      write_status( STATUS_TRUST_MARGINAL );
+      write_trust_status (STATUS_TRUST_MARGINAL, trustlevel);
       log_info(_("WARNING: This key is not certified with"
                  " sufficiently trusted signatures!\n"));
       log_info(_("         It is not certain that the"
                  " signature belongs to the owner.\n" ));
-      print_fingerprint (pk, 1);
+      print_fingerprint (NULL, pk, 1);
       break;
 
     case TRUST_FULLY:
-      write_status( STATUS_TRUST_FULLY );
+      write_trust_status (STATUS_TRUST_FULLY, trustlevel);
       if (opt.with_fingerprint)
-        print_fingerprint (pk, 1);
+        print_fingerprint (NULL, pk, 1);
       break;
 
     case TRUST_ULTIMATE:
-      write_status( STATUS_TRUST_ULTIMATE );
+      write_trust_status (STATUS_TRUST_ULTIMATE, trustlevel);
       if (opt.with_fingerprint)
-        print_fingerprint (pk, 1);
+        print_fingerprint (NULL, pk, 1);
       break;
     }
 
@@ -670,7 +709,7 @@ void
 release_pk_list (pk_list_t pk_list)
 {
   PK_LIST pk_rover;
-  
+
   for ( ; pk_list; pk_list = pk_rover)
     {
       pk_rover = pk_list->next;
@@ -695,7 +734,7 @@ key_present_in_pk_list(PK_LIST pk_list, PKT_public_key *pk)
  * Return a malloced string with a default recipient if there is any
  */
 static char *
-default_recipient(void)
+default_recipient(ctrl_t ctrl)
 {
     PKT_public_key *pk;
     byte fpr[MAX_FINGERPRINT_LEN+1];
@@ -708,7 +747,7 @@ default_recipient(void)
     if( !opt.def_recipient_self )
        return NULL;
     pk = xmalloc_clear( sizeof *pk );
-    i = get_seckey_byname (pk, NULL);
+    i = get_seckey_default (ctrl, pk);
     if( i ) {
        free_public_key( pk );
        return NULL;
@@ -754,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);
@@ -773,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)
+find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
+                    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);
@@ -793,12 +835,24 @@ 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;
+
       /* Key not found or other error. */
-      log_error (_("%s: skipped: %s\n"), name, g10_errstr(rc) );
-      send_status_inv_recp (0, name);
+      log_error (_("%s: skipped: %s\n"), name, gpg_strerror (rc) );
+      switch (gpg_err_code (rc))
+        {
+        case GPG_ERR_NO_SECKEY:
+        case GPG_ERR_NO_PUBKEY:   code =  1; break;
+        case GPG_ERR_INV_USER_ID: code = 14; break;
+        default: code = 0; break;
+        }
+      send_status_inv_recp (code, name);
       free_public_key (pk);
       return rc;
     }
@@ -807,43 +861,48 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
   if (rc)
     {
       /* Key found but not usable for us (e.g. sign-only key). */
-      send_status_inv_recp (0, name);
-      log_error (_("%s: skipped: %s\n"), name, g10_errstr(rc) );
+      send_status_inv_recp (3, name); /* Wrong key usage */
+      log_error (_("%s: skipped: %s\n"), name, gpg_strerror (rc) );
       free_public_key (pk);
       return rc;
     }
 
   /* Key found and usable.  Check validity. */
-  trustlevel = get_validity (pk, pk->user_id);
-  if ( (trustlevel & TRUST_FLAG_DISABLED) ) 
+  if (!from_file)
     {
-      /* Key has been disabled. */
-      send_status_inv_recp (0, name);
-      log_info (_("%s: skipped: public key is disabled\n"), name);
-      free_public_key (pk);
-      return G10ERR_UNU_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 G10ERR_UNU_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.  */
-  if (!key_present_in_pk_list (*pk_list_addr, pk)) 
+  if (!key_present_in_pk_list (*pk_list_addr, pk))
     {
-      log_info (_("%s: skipped: public key already present\n"), name);
+      if (!opt.quiet)
+        log_info (_("%s: skipped: public key already present\n"), name);
       free_public_key (pk);
     }
   else
     {
       pk_list_t r;
-      
+
       r = xtrymalloc (sizeof *r);
       if (!r)
         {
@@ -856,35 +915,34 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
       r->flags = mark_hidden? 1:0;
       *pk_list_addr = r;
     }
-  
+
   return 0;
 }
 
 
 
 /* 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: This is an encrypt-to recipient.
    Bit 1: 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.
* 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, 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;
@@ -892,6 +950,7 @@ build_pk_list (ctrl_t ctrl,
   int any_recipients=0;
   strlist_t rov,remusr;
   char *def_rec = NULL;
+  char pkstrbuf[PUBKEY_STRING_SIZE];
 
   /* Try to expand groups if any have been defined. */
   if (opt.grouplist)
@@ -899,11 +958,65 @@ build_pk_list (ctrl_t ctrl,
   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;
+
+      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 ) 
+  for ( rov = remusr; rov; rov = rov->next )
     {
-      if ( !(rov->flags & 1) )
+      if ( !(rov->flags & PK_LIST_ENCRYPT_TO) )
         {
           /* This is a regular recipient; i.e. not an encrypt-to
              one. */
@@ -911,7 +1024,7 @@ build_pk_list (ctrl_t ctrl,
 
           /* Hidden recipients are not allowed while in PGP mode,
              issue a warning and switch into GnuPG mode. */
-          if ((rov->flags&2) && (PGP2 || PGP6 || PGP7 || PGP8))
+          if ((rov->flags & PK_LIST_HIDDEN) && (PGP6 || PGP7 || PGP8))
             {
               log_info(_("you may not use %s while in %s mode\n"),
                        "--hidden-recipient",
@@ -920,33 +1033,35 @@ 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 1for the second last argument and 1 as the last
+             we pass 1 for the second last argument and 1 as the last
              argument to disable AKL. */
           if ( (rc = get_pubkey_byname (ctrl,
-                                        NULL, pk, rov->d, NULL, NULL, 1, 1)) ) 
+                                        NULL, pk, rov->d, NULL, NULL, 1, 1)) )
             {
               free_public_key ( pk ); pk = NULL;
-              log_error (_("%s: skipped: %s\n"), rov->d, g10_errstr(rc) );
+              log_error (_("%s: skipped: %s\n"), rov->d, gpg_strerror (rc) );
               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. */
               if (key_present_in_pk_list(pk_list, pk) == 0)
                 {
                   free_public_key (pk); pk = NULL;
-                  log_info (_("%s: skipped: public key already present\n"),
-                            rov->d);
+                  if (!opt.quiet)
+                    log_info (_("%s: skipped: public key already present\n"),
+                              rov->d);
                 }
               else
                 {
@@ -954,13 +1069,13 @@ build_pk_list (ctrl_t ctrl,
                   r = xmalloc( sizeof *r );
                   r->pk = pk; pk = NULL;
                   r->next = pk_list;
-                  r->flags = (rov->flags&2)?1:0;
+                  r->flags = (rov->flags&PK_LIST_HIDDEN)?1:0;
                   pk_list = r;
 
                   /* Hidden encrypt-to recipients are not allowed while
                      in PGP mode, issue a warning and switch into
                      GnuPG mode. */
-                  if ((r->flags&1) && (PGP2 || PGP6 || PGP7 || PGP8))
+                  if ((r->flags&PK_LIST_ENCRYPT_TO) && (PGP6 || PGP7 || PGP8))
                     {
                       log_info(_("you may not use %s while in %s mode\n"),
                                "--hidden-encrypt-to",
@@ -970,13 +1085,12 @@ build_pk_list (ctrl_t ctrl,
                     }
                 }
             }
-          else 
+          else
             {
-              /* The public key is not usable for encryption or not
-                 available. */
+              /* The public key is not usable for encryption. */
               free_public_key( pk ); pk = NULL;
-              log_error(_("%s: skipped: %s\n"), rov->d, g10_errstr(rc) );
-              send_status_inv_recp (0, rov->d);
+              log_error(_("%s: skipped: %s\n"), rov->d, gpg_strerror (rc) );
+              send_status_inv_recp (3, rov->d); /* Wrong key usage */
               goto fail;
             }
         }
@@ -984,20 +1098,20 @@ build_pk_list (ctrl_t ctrl,
 
   /* If we don't have any recipients yet and we are not in batch mode
      drop into interactive selection mode. */
-  if ( !any_recipients && !opt.batch ) 
-    { 
+  if ( !any_recipients && !opt.batch )
+    {
       int have_def_rec;
       char *answer = NULL;
       strlist_t backlog = NULL;
 
       if (pk_list)
         any_recipients = 1;
-      def_rec = default_recipient();
+      def_rec = default_recipient(ctrl);
       have_def_rec = !!def_rec;
       if ( !have_def_rec )
         tty_printf(_("You did not specify a user ID. (you may use \"-r\")\n"));
 
-      for (;;) 
+      for (;;)
         {
           rc = 0;
           xfree(answer);
@@ -1007,7 +1121,7 @@ build_pk_list (ctrl_t ctrl,
               answer = def_rec;
               def_rec = NULL;
             }
-          else if (backlog) 
+          else if (backlog)
             {
               /* This is part of our trick to expand and display groups. */
               answer = strlist_pop (&backlog);
@@ -1025,11 +1139,11 @@ build_pk_list (ctrl_t ctrl,
                   u32 keyid[2];
 
                   keyid_from_pk(iter->pk,keyid);
-                  tty_printf("%4u%c/%s %s \"",
-                             nbits_from_pk(iter->pk),
-                             pubkey_letter(iter->pk->pubkey_algo),
-                             keystr(keyid),
-                             datestr_from_pk(iter->pk));
+                  tty_printf ("%s/%s %s \"",
+                              pubkey_string (iter->pk,
+                                             pkstrbuf, sizeof pkstrbuf),
+                              keystr(keyid),
+                              datestr_from_pk (iter->pk));
 
                   if (iter->pk->user_id)
                     tty_print_utf8_string(iter->pk->user_id->name,
@@ -1050,35 +1164,36 @@ build_pk_list (ctrl_t ctrl,
               trim_spaces(answer);
               cpr_kill_prompt();
             }
-          
-          if ( !answer || !*answer ) 
+
+          if ( !answer || !*answer )
             {
               xfree(answer);
               break;  /* No more recipients entered - get out of loop. */
             }
 
           /* Do group expand here too.  The trick here is to continue
-             the loop if any expansion occured.  The code above will
+             the loop if any expansion occurred.  The code above will
              then list all expanded keys. */
           if (expand_id(answer,&backlog,0))
             continue;
 
           /* Get and check key for the current name. */
-          if (pk)
-            free_public_key (pk);
+          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 )
                 {
                   /* No validation for a default recipient. */
-                  if (!key_present_in_pk_list(pk_list, pk)) 
+                  if (!key_present_in_pk_list(pk_list, pk))
                     {
-                      free_public_key (pk); pk = NULL;
+                      free_public_key (pk);
+                      pk = NULL;
                       log_info (_("skipped: public key "
                                   "already set as default recipient\n") );
                     }
@@ -1096,19 +1211,21 @@ build_pk_list (ctrl_t ctrl,
               else
                 { /* Check validity of this key. */
                   int trustlevel;
-                   
-                  trustlevel = get_validity (pk, pk->user_id);
-                  if ( (trustlevel & TRUST_FLAG_DISABLED) ) 
+
+                  trustlevel =
+                    get_validity (ctrl, NULL, pk, pk->user_id, NULL, 1);
+                  if ( (trustlevel & TRUST_FLAG_DISABLED) )
                     {
                       tty_printf (_("Public key is disabled.\n") );
                     }
-                  else if ( do_we_trust_pre (pk, trustlevel) ) 
+                  else if ( do_we_trust_pre (pk, trustlevel) )
                     {
                       /* Skip the actual key if the key is already
                        * present in the list */
                       if (!key_present_in_pk_list(pk_list, pk))
                         {
-                          free_public_key(pk); pk = NULL;
+                          free_public_key (pk);
+                          pk = NULL;
                           log_info(_("skipped: public key already set\n") );
                         }
                       else
@@ -1134,18 +1251,19 @@ build_pk_list (ctrl_t ctrl,
           pk = NULL;
         }
     }
-  else if ( !any_recipients && (def_rec = default_recipient()) ) 
+  else if ( !any_recipients && (def_rec = default_recipient(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
@@ -1155,7 +1273,7 @@ build_pk_list (ctrl_t ctrl,
           if (!key_present_in_pk_list(pk_list, pk))
             log_info (_("skipped: public key already set "
                         "as default recipient\n"));
-          else 
+          else
             {
               PK_LIST r = xmalloc( sizeof *r );
               r->pk = pk; pk = NULL;
@@ -1171,30 +1289,55 @@ build_pk_list (ctrl_t ctrl,
         }
       xfree(def_rec); def_rec = NULL;
     }
-  else 
+  else
     {
       /* General case: Check all keys. */
       any_recipients = 0;
-      for (; remusr; remusr = remusr->next ) 
+      for (; remusr; remusr = remusr->next )
         {
-          if ( (remusr->flags & 1) )
+          if ( (remusr->flags & PK_LIST_ENCRYPT_TO) )
             continue; /* encrypt-to keys are already handled. */
 
-          rc = find_and_check_key (ctrl, remusr->d, use, !!(remusr->flags&2),
+          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;
           any_recipients = 1;
         }
     }
-  
-  if ( !rc && !any_recipients ) 
+
+  if ( !rc && !any_recipients )
     {
       log_error(_("no valid addressees\n"));
       write_status_text (STATUS_NO_RECP, "0");
-      rc = G10ERR_NO_USER_ID;
+      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 )
@@ -1233,7 +1376,7 @@ algo_available( preftype_t preftype, int algo, const union pref_hint *hint)
                  && algo != CIPHER_ALGO_3DES
                  && algo != CIPHER_ALGO_CAST5))
        return 0;
-      
+
       if(PGP7 && (algo != CIPHER_ALGO_IDEA
                  && algo != CIPHER_ALGO_3DES
                  && algo != CIPHER_ALGO_CAST5
@@ -1303,9 +1446,8 @@ select_algo_from_prefs(PK_LIST pk_list, int preftype,
   u32 bits[8];
   const prefitem_t *prefs;
   int result=-1,i;
-  unsigned int best=-1;    
-  byte scores[256];
-    
+  u16 scores[256];
+
   if( !pk_list )
     return -1;
 
@@ -1327,10 +1469,7 @@ select_algo_from_prefs(PK_LIST pk_list, int preftype,
             dropped from 4880 but is still relevant to GPG's 1991
             support.  All this doesn't mean IDEA is actually
             available, of course. */
-         if(PGP2 && pkr->pk->version<4 && pkr->pk->selfsigversion<4)
-           implicit=CIPHER_ALGO_IDEA;
-         else
-           implicit=CIPHER_ALGO_3DES;
+          implicit=CIPHER_ALGO_3DES;
 
          break;
 
@@ -1342,12 +1481,7 @@ select_algo_from_prefs(PK_LIST pk_list, int preftype,
             mode, and that's the only time PREFTYPE_HASH is used
             anyway. -dms */
 
-         /* MD5 is there for v3 keys with v3 selfsigs when --pgp2 is
-            on. */
-         if(PGP2 && pkr->pk->version<4 && pkr->pk->selfsigversion<4)
-           implicit=DIGEST_ALGO_MD5;
-         else
-           implicit=DIGEST_ALGO_SHA1;
+          implicit=DIGEST_ALGO_SHA1;
 
          break;
 
@@ -1367,7 +1501,13 @@ select_algo_from_prefs(PK_LIST pk_list, int preftype,
            {
              if( prefs[i].type == preftype )
                {
-                 scores[prefs[i].value]+=rank;
+                 /* Make sure all scores don't add up past 0xFFFF
+                    (and roll around) */
+                 if(rank+scores[prefs[i].value]<=0xFFFF)
+                   scores[prefs[i].value]+=rank;
+                 else
+                   scores[prefs[i].value]=0xFFFF;
+
                  mask[prefs[i].value/32] |= 1<<(prefs[i].value%32);
 
                  rank++;
@@ -1434,10 +1574,31 @@ select_algo_from_prefs(PK_LIST pk_list, int preftype,
 
   if(result==-1)
     {
+      unsigned int best=-1;
+
       /* At this point, we have not selected an algorithm due to a
         special request or via personal prefs.  Pick the highest
         ranked algorithm (i.e. the one with the lowest score). */
 
+      if(preftype==PREFTYPE_HASH && scores[DIGEST_ALGO_MD5])
+       {
+         /* "If you are building an authentication system, the recipient
+            may specify a preferred signing algorithm. However, the
+            signer would be foolish to use a weak algorithm simply
+            because the recipient requests it." (RFC4880:14).  If any
+            other hash algorithm is available, pretend that MD5 isn't.
+            Note that if the user intentionally chose MD5 by putting it
+            in their personal prefs, then we do what the user said (as we
+            never reach this code). */
+
+         for(i=DIGEST_ALGO_MD5+1;i<256;i++)
+           if(scores[i])
+             {
+               scores[DIGEST_ALGO_MD5]=0;
+               break;
+             }
+       }
+
       for(i=0;i<256;i++)
        {
          /* Note the '<' here.  This means in case of a tie, we will
@@ -1455,18 +1616,6 @@ select_algo_from_prefs(PK_LIST pk_list, int preftype,
              result=i;
            }
        }
-
-      /* "If you are building an authentication system, the recipient
-        may specify a preferred signing algorithm. However, the
-        signer would be foolish to use a weak algorithm simply
-        because the recipient requests it." (RFC4880:14).  If we
-        settle on MD5, and SHA1 is also available, use SHA1 instead.
-        Note that if the user intentionally chose MD5 by putting it
-        in their personal prefs, then we do what the user said (as we
-        never reach this code). */
-      if(preftype==PREFTYPE_HASH && result==DIGEST_ALGO_MD5
-        && (bits[0] & (1<<DIGEST_ALGO_SHA1)))
-       result=DIGEST_ALGO_SHA1;
     }
 
   return result;
@@ -1483,15 +1632,15 @@ select_mdc_from_pklist (PK_LIST pk_list)
 
   if ( !pk_list )
     return 0;
-  
-  for (pkr = pk_list; pkr; pkr = pkr->next) 
+
+  for (pkr = pk_list; pkr; pkr = pkr->next)
     {
       int mdc;
-      
+
       if (pkr->pk->user_id) /* selected by user ID */
         mdc = pkr->pk->user_id->flags.mdc;
       else
-        mdc = pkr->pk->mdc_feature;
+        mdc = pkr->pk->flags.mdc;
       if (!mdc)
         return 0;  /* At least one recipient does not support it. */
     }
@@ -1504,15 +1653,15 @@ void
 warn_missing_mdc_from_pklist (PK_LIST pk_list)
 {
   PK_LIST pkr;
-  
-  for (pkr = pk_list; pkr; pkr = pkr->next) 
+
+  for (pkr = pk_list; pkr; pkr = pkr->next)
     {
       int mdc;
 
       if (pkr->pk->user_id) /* selected by user ID */
         mdc = pkr->pk->user_id->flags.mdc;
       else
-        mdc = pkr->pk->mdc_feature;
+        mdc = pkr->pk->flags.mdc;
       if (!mdc)
         log_info (_("Note: key %s has no %s feature\n"),
                   keystr_from_pk (pkr->pk), "MDC");
@@ -1523,8 +1672,8 @@ void
 warn_missing_aes_from_pklist (PK_LIST pk_list)
 {
   PK_LIST pkr;
-  for (pkr = pk_list; pkr; pkr = pkr->next) 
+
+  for (pkr = pk_list; pkr; pkr = pkr->next)
     {
       const prefitem_t *prefs;
       int i;
@@ -1534,7 +1683,7 @@ warn_missing_aes_from_pklist (PK_LIST pk_list)
       if (prefs)
         {
           for (i=0; !gotit && prefs[i].type; i++ )
-            if (prefs[i].type == PREFTYPE_SYM 
+            if (prefs[i].type == PREFTYPE_SYM
                 && prefs[i].value == CIPHER_ALGO_AES)
               gotit++;
        }