* keyserver.c (keyserver_spawn): Use the full 64-bit keyid in the INFO
[gnupg.git] / g10 / import.c
index 905e2d8..60b8ff2 100644 (file)
@@ -1,5 +1,6 @@
 /* import.c
- * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
+ *               2004 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -60,7 +61,6 @@ static int import( IOBUF inp, const char* fname,
                    struct stats_s *stats, unsigned int options );
 static int read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root );
 static void revocation_present(KBNODE keyblock);
-static void remove_bad_stuff (KBNODE keyblock);
 static int import_one( const char *fname, KBNODE keyblock,
                        struct stats_s *stats, unsigned int options);
 static int import_secret_one( const char *fname, KBNODE keyblock,
@@ -84,52 +84,20 @@ static int merge_keysigs( KBNODE dst, KBNODE src, int *n_sigs,
                             const char *fname, u32 *keyid );
 
 int
-parse_import_options(char *str,unsigned int *options)
+parse_import_options(char *str,unsigned int *options,int noisy)
 {
-  char *tok;
-  int hit=0;
-  struct
-  {
-    char *name;
-    unsigned int bit;
-  } import_opts[]=
+  struct parse_options import_opts[]=
     {
-      {"allow-local-sigs",IMPORT_ALLOW_LOCAL_SIGS},
-      {"repair-hkp-subkey-bug",IMPORT_REPAIR_PKS_SUBKEY_BUG},
-      {"repair-pks-subkey-bug",IMPORT_REPAIR_PKS_SUBKEY_BUG},
-      {"fast-import",IMPORT_FAST_IMPORT},
-      {"convert-sk-to-pk",IMPORT_SK2PK},
-      {NULL,0}
+      {"allow-local-sigs",IMPORT_ALLOW_LOCAL_SIGS,NULL},
+      {"repair-hkp-subkey-bug",IMPORT_REPAIR_PKS_SUBKEY_BUG,NULL},
+      {"repair-pks-subkey-bug",IMPORT_REPAIR_PKS_SUBKEY_BUG,NULL},
+      {"fast-import",IMPORT_FAST_IMPORT,NULL},
+      {"convert-sk-to-pk",IMPORT_SK2PK,NULL},
+      {"merge-only",IMPORT_MERGE_ONLY,NULL},
+      {NULL,0,NULL}
     };
 
-  while((tok=strsep(&str," ,")))
-    {
-      int i,rev=0;
-
-      if(ascii_strncasecmp("no-",tok,3)==0)
-       {
-         rev=1;
-         tok+=3;
-       }
-
-      for(i=0;import_opts[i].name;i++)
-       {
-         if(ascii_strcasecmp(import_opts[i].name,tok)==0)
-           {
-             if(rev)
-               *options&=~import_opts[i].bit;
-             else
-               *options|=import_opts[i].bit;
-             hit=1;
-             break;
-           }
-       }
-
-      if(!hit && !import_opts[i].name)
-       return 0;
-    }
-
-  return hit;
+  return parse_options(str,options,import_opts,noisy);
 }
 
 void *
@@ -202,6 +170,8 @@ import_keys_internal( IOBUF inp, char **fnames, int nnames,
            else {
                rc = import( inp2, fname, stats, options );
                iobuf_close(inp2);
+                /* Must invalidate that ugly cache to actually close it. */
+                iobuf_ioctl (NULL, 2, 0, (char*)fname);
                if( rc )
                    log_error("import from `%s' failed: %s\n", fname,
                                      g10_errstr(rc) );
@@ -260,7 +230,6 @@ import( IOBUF inp, const char* fname,
     }
 
     while( !(rc = read_block( inp, &pending_pkt, &keyblock) )) {
-        remove_bad_stuff (keyblock);
        if( keyblock->pkt->pkttype == PKT_PUBLIC_KEY )
            rc = import_one( fname, keyblock, stats, options );
        else if( keyblock->pkt->pkttype == PKT_SECRET_KEY ) 
@@ -396,17 +365,17 @@ read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root )
        /* make a linked list of all packets */
        switch( pkt->pkttype ) {
          case PKT_COMPRESSED:
-           if( pkt->pkt.compressed->algorithm < 1
-               || pkt->pkt.compressed->algorithm > 2 ) {
+           if(check_compress_algo(pkt->pkt.compressed->algorithm))
+             {
                rc = G10ERR_COMPR_ALGO;
                goto ready;
-           }
-           {
+             }
+           else
+             {
                compress_filter_context_t *cfx = m_alloc_clear( sizeof *cfx );
-               cfx->algo = pkt->pkt.compressed->algorithm;
                pkt->pkt.compressed->buf = NULL;
-               iobuf_push_filter2( a, compress_filter, cfx, 1 );
-           }
+               push_compress_filter2(a,cfx,pkt->pkt.compressed->algorithm,1);
+             }
            free_packet( pkt );
            init_packet(pkt);
            break;
@@ -450,22 +419,6 @@ read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root )
     return rc;
 }
 
-
-static void
-remove_bad_stuff (KBNODE keyblock)
-{
-    KBNODE node;
-
-    for (node=keyblock; node; node = node->next ) {
-        if( node->pkt->pkttype == PKT_SIGNATURE ) {
-            /* delete the subpackets we used to use for the
-               verification cache */
-            delete_sig_subpkt (node->pkt->pkt.signature->unhashed,
-                               SIGSUBPKT_PRIV_VERIFY_CACHE);
-        }
-    }
-}
-
 /* Walk through the subkeys on a pk to find if we have the PKS
    disease: multiple subkeys with their binding sigs stripped, and the
    sig for the first subkey placed after the last subkey.  That is,
@@ -556,7 +509,7 @@ print_import_ok (PKT_public_key *pk, PKT_secret_key *sk, unsigned int reason)
   write_status_text (STATUS_IMPORT_OK, buf);
 }
 
-void
+static void
 print_import_check (PKT_public_key * pk, PKT_user_id * id)
 {
     char * buf;
@@ -578,6 +531,114 @@ print_import_check (PKT_public_key * pk, PKT_user_id * id)
     m_free (buf);
 }
 
+static void
+check_prefs(KBNODE keyblock)
+{
+  KBNODE node;
+  u32 keyid[2];
+  int problem=0;
+  
+  merge_keys_and_selfsig(keyblock);
+  keyid_from_pk(keyblock->pkt->pkt.public_key,keyid);
+
+  for(node=keyblock;node;node=node->next)
+    {
+      if(node->pkt->pkttype==PKT_USER_ID
+        && node->pkt->pkt.user_id->created
+        && node->pkt->pkt.user_id->prefs)
+       {
+         PKT_user_id *uid=node->pkt->pkt.user_id;
+         prefitem_t *prefs=uid->prefs;
+         char *user=utf8_to_native(uid->name,strlen(uid->name),0);
+
+         for(;prefs->type;prefs++)
+           {
+             char num[10]; /* prefs->value is a byte, so we're over
+                              safe here */
+
+             sprintf(num,"%u",prefs->value);
+
+             if(prefs->type==PREFTYPE_SYM)
+               {
+                 if(check_cipher_algo(prefs->value))
+                   {
+                     const char *algo=cipher_algo_to_string(prefs->value);
+                     if(!problem)
+                       log_info(_("WARNING: key %08lX contains preferences"
+                                  " for unavailable algorithms:\n"),
+                                (ulong)keyid[1]);
+                     log_info(_("         \"%s\": preference for cipher"
+                                " algorithm %s\n"),user,algo?algo:num);
+                     problem=1;
+                   }
+               }
+             else if(prefs->type==PREFTYPE_HASH)
+               {
+                 if(check_digest_algo(prefs->value))
+                   {
+                     const char *algo=digest_algo_to_string(prefs->value);
+                     if(!problem)
+                       log_info(_("WARNING: key %08lX contains preferences"
+                                  " for unavailable algorithms:\n"),
+                                (ulong)keyid[1]);
+                     log_info(_("         \"%s\": preference for digest"
+                                " algorithm %s\n"),user,algo?algo:num);
+                     problem=1;
+                   }
+               }
+             else if(prefs->type==PREFTYPE_ZIP)
+               {
+                 if(check_compress_algo(prefs->value))
+                   {
+                     const char *algo=compress_algo_to_string(prefs->value);
+                     if(!problem)
+                       log_info(_("WARNING: key %08lX contains preferences"
+                                  " for unavailable algorithms:\n"),
+                                (ulong)keyid[1]);
+                     log_info(_("         \"%s\": preference for compression"
+                                " algorithm %s\n"),user,algo?algo:num);
+                     problem=1;
+                   }
+               }
+           }
+
+         m_free(user);
+       }
+    }
+
+  if(problem)
+    {
+      log_info(_("it is strongly suggested that you update"
+                " your preferences and\n"));
+      log_info(_("re-distribute this key to avoid potential algorithm"
+                " mismatch problems\n"));
+
+      if(!opt.batch)
+       {
+         STRLIST sl=NULL,locusr=NULL;
+         size_t fprlen=0;
+         byte fpr[MAX_FINGERPRINT_LEN],*p;
+         char username[(MAX_FINGERPRINT_LEN*2)+1];
+         unsigned int i;
+
+         p=fingerprint_from_pk(keyblock->pkt->pkt.public_key,fpr,&fprlen);
+         for(i=0;i<fprlen;i++,p++)
+           sprintf(username+2*i,"%02X",*p);
+         add_to_strlist(&locusr,username);
+
+         append_to_strlist(&sl,"updpref");
+         append_to_strlist(&sl,"save");
+
+         keyedit_menu( username, locusr, sl, 1, 1 );
+         free_strlist(sl);
+         free_strlist(locusr);
+       }
+      else if(!opt.quiet)
+       log_info(_("you can update your preferences with:"
+                  " gpg --edit-key %08lX updpref save\n"),(ulong)keyid[1]);
+    }
+}
+
 /****************
  * Try to import one keyblock. Return an error only in serious cases, but
  * never for an invalid keyblock.  It uses log_error to increase the
@@ -607,10 +668,6 @@ import_one( const char *fname, KBNODE keyblock,
     keyid_from_pk( pk, keyid );
     uidnode = find_next_kbnode( keyblock, PKT_USER_ID );
 
-    if(pk->pubkey_algo==PUBKEY_ALGO_ELGAMAL)
-      log_info(_("NOTE: Elgamal primary key detected - "
-                "this may take some time to import\n"));
-
     if( opt.verbose && !opt.interactive ) {
        log_info( "pub  %4u%c/%08lX %s   ",
                  nbits_from_pk( pk ),
@@ -640,7 +697,8 @@ import_one( const char *fname, KBNODE keyblock,
 
     clear_kbnode_flags( keyblock );
 
-    if((options&IMPORT_REPAIR_PKS_SUBKEY_BUG) && fix_pks_corruption(keyblock))
+    if((options&IMPORT_REPAIR_PKS_SUBKEY_BUG) && fix_pks_corruption(keyblock)
+       && opt.verbose)
       log_info(_("key %08lX: PKS subkey corruption repaired\n"),
               (ulong)keyid[1]);
 
@@ -662,11 +720,9 @@ import_one( const char *fname, KBNODE keyblock,
          }
 
     if( !delete_inv_parts( fname, keyblock, keyid, options ) ) {
-       if( !opt.quiet ) {
-           log_info( _("key %08lX: no valid user IDs\n"),
-                                                       (ulong)keyid[1]);
-           log_info(_("this may be caused by a missing self-signature\n"));
-       }
+        log_error( _("key %08lX: no valid user IDs\n"), (ulong)keyid[1]);
+       if( !opt.quiet )
+         log_info(_("this may be caused by a missing self-signature\n"));
        stats->no_user_id++;
        return 0;
     }
@@ -678,12 +734,13 @@ import_one( const char *fname, KBNODE keyblock,
        log_error( _("key %08lX: public key not found: %s\n"),
                                (ulong)keyid[1], g10_errstr(rc));
     }
-    else if ( rc && opt.merge_only ) {
+    else if ( rc && (opt.import_options&IMPORT_MERGE_ONLY) )
+      {
        if( opt.verbose )
-           log_info( _("key %08lX: new key - skipped\n"), (ulong)keyid[1] );
+         log_info( _("key %08lX: new key - skipped\n"), (ulong)keyid[1] );
        rc = 0;
        stats->skipped_new_keys++;
-    }
+      }
     else if( rc ) { /* insert this key */
         KEYDB_HANDLE hd = keydb_new (0);
 
@@ -820,27 +877,47 @@ import_one( const char *fname, KBNODE keyblock,
                  print_import_ok (pk, NULL,
                                   ((n_uids?2:0)|(n_sigs?4:0)|(n_subk?8:0)));
        }
-       else {
-             if (is_status_enabled ()) 
-                  print_import_ok (pk, NULL, 0);
-       
-           if( !opt.quiet ) {
-               char *p=get_user_id_printable(keyid);
+       else
+         {
+           if (is_status_enabled ()) 
+             print_import_ok (pk, NULL, 0);
+
+           if( !opt.quiet )
+             {
+               char *p=get_user_id_printable(keyid);
                log_info( _("key %08lX: \"%s\" not changed\n"),
                          (ulong)keyid[1],p);
                m_free(p);
-           }
+             }
+
            stats->unchanged++;
-       }
+         }
+
         keydb_release (hd); hd = NULL;
     }
 
   leave:
+
+    /* Now that the key is definitely incorporated into the keydb, we
+       need to check if a designated revocation is present or if the
+       prefs are not rational so we can warn the user. */
+
+    if(mod_key)
+      {
+       revocation_present(keyblock_orig);
+       if(seckey_available(keyid)==0)
+         check_prefs(keyblock_orig);
+      }
+    else if(new_key)
+      {
+       revocation_present(keyblock);
+       if(seckey_available(keyid)==0)
+         check_prefs(keyblock);
+      }
+
     release_kbnode( keyblock_orig );
     free_public_key( pk_orig );
 
-    revocation_present(keyblock);
-
     return rc;
 }
 
@@ -879,7 +956,12 @@ sec_to_pub_keyblock(KBNODE sec_keyblock)
 
          n=pubkey_get_npkey(pk->pubkey_algo);
          if(n==0)
-           pk->pkey[0]=mpi_copy(sk->skey[0]);
+           {
+             /* we can't properly extract the pubkey without knowing
+                the number of MPIs */
+             release_kbnode(pub_keyblock);
+             return NULL;
+           }
          else
            {
              int i;
@@ -956,38 +1038,52 @@ import_secret_one( const char *fname, KBNODE keyblock,
 
     /* do we have this key already in one of our secrings ? */
     rc = seckey_available( keyid );
-    if( rc == G10ERR_NO_SECKEY && !opt.merge_only ) { /* simply insert this key */
+    if( rc == G10ERR_NO_SECKEY && !(opt.import_options&IMPORT_MERGE_ONLY) )
+      {
+       /* simply insert this key */
         KEYDB_HANDLE hd = keydb_new (1);
 
        /* get default resource */
         rc = keydb_locate_writable (hd, NULL);
        if (rc) {
-           log_error (_("no default secret keyring: %s\n"), g10_errstr (rc));
-            keydb_release (hd);
-           return G10ERR_GENERAL;
+         log_error (_("no default secret keyring: %s\n"), g10_errstr (rc));
+         keydb_release (hd);
+         return G10ERR_GENERAL;
        }
        rc = keydb_insert_keyblock (hd, keyblock );
         if (rc)
-           log_error (_("error writing keyring `%s': %s\n"),
-                       keydb_get_resource_name (hd), g10_errstr(rc) );
+         log_error (_("error writing keyring `%s': %s\n"),
+                    keydb_get_resource_name (hd), g10_errstr(rc) );
         keydb_release (hd);
        /* we are ready */
        if( !opt.quiet )
-           log_info( _("key %08lX: secret key imported\n"), (ulong)keyid[1]);
+         log_info( _("key %08lX: secret key imported\n"), (ulong)keyid[1]);
        stats->secret_imported++;
         if (is_status_enabled ()) 
-             print_import_ok (NULL, sk, 1|16);
+         print_import_ok (NULL, sk, 1|16);
 
        if(options&IMPORT_SK2PK)
          {
            /* Try and make a public key out of this. */
 
            KBNODE pub_keyblock=sec_to_pub_keyblock(keyblock);
-           import_one(fname,pub_keyblock,stats,opt.import_options);
-           release_kbnode(pub_keyblock);
+           if(pub_keyblock)
+             {
+               import_one(fname,pub_keyblock,stats,opt.import_options);
+               release_kbnode(pub_keyblock);
+             }
          }
 
-    }
+       /* Now that the key is definitely incorporated into the keydb,
+          if we have the public part of this key, we need to check if
+          the prefs are rational. */
+       node=get_pubkeyblock(keyid);
+       if(node)
+         {
+           check_prefs(node);
+           release_kbnode(node);
+         }
+      }
     else if( !rc ) { /* we can't merge secret keys */
        log_error( _("key %08lX: already in secret keyring\n"),
                                                        (ulong)keyid[1]);
@@ -1028,8 +1124,8 @@ import_revoke_cert( const char *fname, KBNODE node, struct stats_s *stats )
     pk = m_alloc_clear( sizeof *pk );
     rc = get_pubkey( pk, keyid );
     if( rc == G10ERR_NO_PUBKEY ) {
-       log_info( _("key %08lX: no public key - "
-                "can't apply revocation certificate\n"), (ulong)keyid[1]);
+       log_error( _("key %08lX: no public key - "
+                    "can't apply revocation certificate\n"), (ulong)keyid[1]);
        rc = 0;
        goto leave;
     }
@@ -1079,12 +1175,12 @@ import_revoke_cert( const char *fname, KBNODE node, struct stats_s *stats )
        if( onode->pkt->pkttype == PKT_USER_ID )
            break;
        else if( onode->pkt->pkttype == PKT_SIGNATURE
-                && onode->pkt->pkt.signature->sig_class == 0x20
-                && keyid[0] == onode->pkt->pkt.signature->keyid[0]
-                && keyid[1] == onode->pkt->pkt.signature->keyid[1] ) {
+                && !cmp_signatures(node->pkt->pkt.signature,
+                                   onode->pkt->pkt.signature))
+         {
            rc = 0;
            goto leave; /* yes, we already know about it */
-       }
+         }
     }
 
 
@@ -1105,6 +1201,13 @@ import_revoke_cert( const char *fname, KBNODE node, struct stats_s *stats )
        m_free(p);
     }
     stats->n_revoc++;
+
+    /* If the key we just revoked was ultimately trusted, remove its
+       ultimate trust.  This doesn't stop the user from putting the
+       ultimate trust back, but is a reasonable solution for now. */
+    if(get_ownertrust(pk)==TRUST_ULTIMATE)
+      clear_ownertrusts(pk);
+
     revalidation_mark ();
 
   leave:
@@ -1167,15 +1270,18 @@ chk_self_sigs( const char *fname, KBNODE keyblock,
                  rc = check_key_signature( keyblock, n, NULL);
                  if( rc )
                    {
-                     char *p=utf8_to_native(unode->pkt->pkt.user_id->name,
+                     if( opt.verbose )
+                       {
+                         char *p=utf8_to_native(unode->pkt->pkt.user_id->name,
                                      strlen(unode->pkt->pkt.user_id->name),0);
-                     log_info( rc == G10ERR_PUBKEY_ALGO ?
-                               _("key %08lX: unsupported public key "
-                                 "algorithm on user id \"%s\"\n"):
-                               _("key %08lX: invalid self-signature "
-                                 "on user id \"%s\"\n"),
-                               (ulong)keyid[1],p);
-                     m_free(p);
+                         log_info( rc == G10ERR_PUBKEY_ALGO ?
+                                   _("key %08lX: unsupported public key "
+                                     "algorithm on user id \"%s\"\n"):
+                                   _("key %08lX: invalid self-signature "
+                                     "on user id \"%s\"\n"),
+                                   (ulong)keyid[1],p);
+                         m_free(p);
+                       }
                    }
                  else
                    unode->flag |= 1; /* mark that signature checked */
@@ -1187,17 +1293,19 @@ chk_self_sigs( const char *fname, KBNODE keyblock,
                 revocation targets, this may need to be revised. */
 
                if( !knode ) {
-                   log_info( _("key %08lX: no subkey for subkey "
-                               "binding signature\n"),(ulong)keyid[1]);
+                   if(opt.verbose)
+                     log_info( _("key %08lX: no subkey for key binding\n"),
+                               (ulong)keyid[1]);
                    n->flag |= 4; /* delete this */
                }
                else {
                  rc = check_key_signature( keyblock, n, NULL);
                  if( rc ) {
-                   log_info(  rc == G10ERR_PUBKEY_ALGO ?
+                   if(opt.verbose)
+                     log_info(rc == G10ERR_PUBKEY_ALGO ?
                            _("key %08lX: unsupported public key algorithm\n"):
-                           _("key %08lX: invalid subkey binding\n"),
-                           (ulong)keyid[1]);
+                           _("key %08lX: invalid subkey binding\n"),
+                           (ulong)keyid[1]);
                    n->flag|=4;
                  }
                  else {
@@ -1208,8 +1316,9 @@ chk_self_sigs( const char *fname, KBNODE keyblock,
                        bsnode->flag|=4; /* Delete the last binding
                                            sig since this one is
                                            newer */
-                       log_info(_("key %08lX: removed multiple subkey "
-                                  "binding\n"),(ulong)keyid[1]);
+                       if(opt.verbose)
+                         log_info(_("key %08lX: removed multiple subkey "
+                                    "binding\n"),(ulong)keyid[1]);
                      }
 
                      bsnode=n;
@@ -1228,18 +1337,21 @@ chk_self_sigs( const char *fname, KBNODE keyblock,
                  See the comment in getkey.c:merge_selfsigs_subkey for
                  more */
                if( !knode ) {
-                   log_info( _("key %08lX: no subkey for subkey "
-                               "revocation signature\n"),(ulong)keyid[1]);
+                   if(opt.verbose)
+                     log_info( _("key %08lX: no subkey for key revocation\n"),
+                               (ulong)keyid[1]);
                    n->flag |= 4; /* delete this */
                }
                else {
                  rc = check_key_signature( keyblock, n, NULL);
                  if( rc ) {
-                   log_info(  rc == G10ERR_PUBKEY_ALGO ?
+                     if(opt.verbose)
+                       log_info(rc == G10ERR_PUBKEY_ALGO ?
                            _("key %08lX: unsupported public key algorithm\n"):
-                           _("key %08lX: invalid subkey revocation\n"),
-                              (ulong)keyid[1]);
-                   n->flag|=4;
+                           _("key %08lX: invalid subkey revocation\n"),
+                           (ulong)keyid[1]);
+
+                     n->flag|=4;
                  }
                  else {
                    /* It's valid, so is it newer? */
@@ -1248,8 +1360,9 @@ chk_self_sigs( const char *fname, KBNODE keyblock,
                        rsnode->flag|=4; /* Delete the last revocation
                                            sig since this one is
                                            newer */
-                       log_info(_("key %08lX: removed multiple subkey "
-                                  "revocation signatures\n"),(ulong)keyid[1]);
+                       if(opt.verbose)
+                         log_info(_("key %08lX: removed multiple subkey "
+                                    "revocation\n"),(ulong)keyid[1]);
                      }
 
                      rsnode=n;
@@ -1336,18 +1449,18 @@ delete_inv_parts( const char *fname, KBNODE keyblock,
             * to import non-exportable signature when we have the
             * the secret key used to create this signature - it
             * seems that this makes sense */
-           log_info( _("key %08lX: non exportable signature "
-                                   "(class %02x) - skipped\n"),
-                                   (ulong)keyid[1],
-                                    node->pkt->pkt.signature->sig_class );
+           if(opt.verbose)
+             log_info( _("key %08lX: non exportable signature "
+                         "(class %02x) - skipped\n"),
+                       (ulong)keyid[1], node->pkt->pkt.signature->sig_class );
            delete_kbnode( node );
        }
        else if( node->pkt->pkttype == PKT_SIGNATURE
                 && node->pkt->pkt.signature->sig_class == 0x20 )  {
            if( uid_seen ) {
-               log_error( _("key %08lX: revocation certificate "
-                                    "at wrong place - skipped\n"),
-                                   (ulong)keyid[1]);
+               if(opt.verbose)
+                 log_info( _("key %08lX: revocation certificate "
+                             "at wrong place - skipped\n"), (ulong)keyid[1]);
                delete_kbnode( node );
            }
            else {
@@ -1362,9 +1475,10 @@ delete_inv_parts( const char *fname, KBNODE keyblock,
                  int rc = check_key_signature( keyblock, node, NULL);
                  if( rc )
                    {
-                     log_error( _("key %08lX: invalid revocation "
-                                  "certificate: %s - skipped\n"),
-                                (ulong)keyid[1], g10_errstr(rc));
+                     if(opt.verbose)
+                       log_info( _("key %08lX: invalid revocation "
+                                   "certificate: %s - skipped\n"),
+                                 (ulong)keyid[1], g10_errstr(rc));
                      delete_kbnode( node );
                    }
                }
@@ -1374,17 +1488,18 @@ delete_inv_parts( const char *fname, KBNODE keyblock,
                 (node->pkt->pkt.signature->sig_class == 0x18 ||
                  node->pkt->pkt.signature->sig_class == 0x28) &&
                 !subkey_seen ) {
-           log_error( _("key %08lX: subkey signature "
-                        "in wrong place - skipped\n"),
-                      (ulong)keyid[1]);
+           if(opt.verbose)
+             log_info( _("key %08lX: subkey signature "
+                         "in wrong place - skipped\n"), (ulong)keyid[1]);
            delete_kbnode( node );
        }
        else if( node->pkt->pkttype == PKT_SIGNATURE
                 && !IS_CERT(node->pkt->pkt.signature))
          {
-           log_error(_("key %08lX: unexpected signature class (0x%02X) -"
-                       " skipped\n"),(ulong)keyid[1],
-                     node->pkt->pkt.signature->sig_class);
+           if(opt.verbose)
+             log_info(_("key %08lX: unexpected signature class (0x%02X) -"
+                        " skipped\n"),(ulong)keyid[1],
+                      node->pkt->pkt.signature->sig_class);
            delete_kbnode(node);
          }
        else if( (node->flag & 4) ) /* marked for deletion */
@@ -1480,15 +1595,16 @@ collapse_uids( KBNODE *keyblock )
        kid1 = keyid_from_sk( n->pkt->pkt.secret_key, NULL );
     else
        kid1 = 0;
-    log_info(_("key %08lX: duplicated user ID detected - merged\n"),
-                                                                (ulong)kid1);
+    if(!opt.quiet)
+      log_info(_("key %08lX: duplicated user ID detected - merged\n"),
+              (ulong)kid1);
 
     return 1;
 }
 
 /* Check for a 0x20 revocation from a revocation key that is not
-   present.  This gets called without the benefit of merge_xxxx so you
-   can't rely on pk->revkey and friends. */
+   present.  This may be called without the benefit of merge_xxxx so
+   you can't rely on pk->revkey and friends. */
 static void
 revocation_present(KBNODE keyblock)
 {
@@ -1596,23 +1712,25 @@ merge_blocks( const char *fname, KBNODE keyblock_orig, KBNODE keyblock,
                    break;
                else if( onode->pkt->pkttype == PKT_SIGNATURE
                         && onode->pkt->pkt.signature->sig_class == 0x20
-                        && node->pkt->pkt.signature->keyid[0]
-                           == onode->pkt->pkt.signature->keyid[0]
-                        && node->pkt->pkt.signature->keyid[1]
-                           == onode->pkt->pkt.signature->keyid[1] ) {
+                        && !cmp_signatures(onode->pkt->pkt.signature,
+                                           node->pkt->pkt.signature))
+                 {
                    found = 1;
                    break;
-               }
+                 }
            }
            if( !found ) {
-               char *p=get_user_id_printable (keyid);
                KBNODE n2 = clone_kbnode(node);
                insert_kbnode( keyblock_orig, n2, 0 );
                n2->flag |= 1;
                 ++*n_sigs;
-               log_info(_("key %08lX: \"%s\" revocation certificate added\n"),
-                                        (ulong)keyid[1],p);
-               m_free(p);
+               if(!opt.quiet)
+                 {
+                   char *p=get_user_id_printable (keyid);
+                   log_info(_("key %08lX: \"%s\" revocation "
+                              "certificate added\n"), (ulong)keyid[1],p);
+                   m_free(p);
+                 }
            }
        }
     }
@@ -1641,8 +1759,9 @@ merge_blocks( const char *fname, KBNODE keyblock_orig, KBNODE keyblock,
                insert_kbnode( keyblock_orig, n2, 0 );
                n2->flag |= 1;
                 ++*n_sigs;
-               log_info( _("key %08lX: direct key signature added\n"),
-                                        (ulong)keyid[1]);
+               if(!opt.quiet)
+                 log_info( _("key %08lX: direct key signature added\n"),
+                           (ulong)keyid[1]);
            }
        }
     }
@@ -1810,20 +1929,12 @@ merge_sigs( KBNODE dst, KBNODE src, int *n_sigs,
            || n->pkt->pkt.signature->sig_class == 0x28 )
            continue; /* skip signatures which are only valid on subkeys */
        found = 0;
-       for(n2=dst->next; n2 && n2->pkt->pkttype != PKT_USER_ID; n2 = n2->next){
-           if( n2->pkt->pkttype == PKT_SIGNATURE
-               && n->pkt->pkt.signature->keyid[0]
-                  == n2->pkt->pkt.signature->keyid[0]
-               && n->pkt->pkt.signature->keyid[1]
-                  == n2->pkt->pkt.signature->keyid[1]
-               && n->pkt->pkt.signature->timestamp
-                  <= n2->pkt->pkt.signature->timestamp
-               && n->pkt->pkt.signature->sig_class
-                  == n2->pkt->pkt.signature->sig_class ) {
-               found++;
-               break;
+       for(n2=dst->next; n2 && n2->pkt->pkttype != PKT_USER_ID; n2 = n2->next)
+         if(!cmp_signatures(n->pkt->pkt.signature,n2->pkt->pkt.signature))
+           {
+             found++;
+             break;
            }
-       }
        if( !found ) {
            /* This signature is new or newer, append N to DST.
             * We add a clone to the original keyblock, because this