* options.h, g10.c (main), import.c (parse_import_options, import_one,
[gnupg.git] / g10 / import.c
index eb56ee9..2168fe5 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 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,
@@ -68,7 +68,7 @@ static int import_secret_one( const char *fname, KBNODE keyblock,
 static int import_revoke_cert( const char *fname, KBNODE node,
                                struct stats_s *stats);
 static int chk_self_sigs( const char *fname, KBNODE keyblock,
-                         PKT_public_key *pk, u32 *keyid );
+                         PKT_public_key *pk, u32 *keyid, int *non_self );
 static int delete_inv_parts( const char *fname, KBNODE keyblock,
                             u32 *keyid, unsigned int options );
 static int merge_blocks( const char *fname, KBNODE keyblock_orig,
@@ -84,51 +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_HKP_SUBKEY_BUG},
+      {"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},
+      {"merge-only",IMPORT_MERGE_ONLY},
       {NULL,0}
     };
 
-  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 *
@@ -201,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) );
@@ -213,18 +184,19 @@ import_keys_internal( IOBUF inp, char **fnames, int nnames,
         import_print_stats (stats);
         import_release_stats_handle (stats);
     }
-    /* If no fast import and we really added new keys or merged new
-       user ids, signatures or revocations, then update/check the
-       trustdb if the user specified by setting interactive or by
-       not setting no-auto-check-trustdb */
-    if (!(options&IMPORT_FAST_IMPORT) &&
-         (stats->imported || stats->n_uids ||
-          stats->n_sigs || stats->n_revoc)) {
-        if (opt.interactive)
-           update_trustdb();
+    /* If no fast import and the trustdb is dirty (i.e. we added a key
+       or userID that had something other than a selfsig, a signature
+       that was other than a selfsig, or any revocation), then
+       update/check the trustdb if the user specified by setting
+       interactive or by not setting no-auto-check-trustdb */
+    if (!(options&IMPORT_FAST_IMPORT) && trustdb_pending_check())
+      {
+       if (opt.interactive)
+         update_trustdb();
        else if (!opt.no_auto_check_trustdb)
-           check_trustdb();
-    }
+         check_trustdb();
+      }
+
     return rc;
 }
 
@@ -258,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 ) 
@@ -394,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;
@@ -448,23 +419,7 @@ 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 HKP
+/* 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,
    instead of "pk uid sig sub1 bind1 sub2 bind2 sub3 bind3" we have
@@ -474,7 +429,7 @@ remove_bad_stuff (KBNODE keyblock)
    sub2 sub3".  Returns TRUE if the keyblock was modified. */
 
 static int
-fix_hkp_corruption(KBNODE keyblock)
+fix_pks_corruption(KBNODE keyblock)
 {
   int changed=0,keycount=0;
   KBNODE node,last=NULL,sknode=NULL;
@@ -554,6 +509,27 @@ print_import_ok (PKT_public_key *pk, PKT_secret_key *sk, unsigned int reason)
   write_status_text (STATUS_IMPORT_OK, buf);
 }
 
+void
+print_import_check (PKT_public_key * pk, PKT_user_id * id)
+{
+    char * buf;
+    byte fpr[24];
+    u32 keyid[2];
+    size_t i, pos = 0, n;
+
+    buf = m_alloc (17+41+id->len+32);
+    keyid_from_pk (pk, keyid);
+    sprintf (buf, "%08X%08X ", keyid[0], keyid[1]);
+    pos = 17;
+    fingerprint_from_pk (pk, fpr, &n);
+    for (i = 0; i < n; i++, pos += 2)
+        sprintf (buf+pos, "%02X", fpr[i]);
+    strcat (buf, " ");
+    pos += 1;
+    strcat (buf, id->name);
+    write_status_text (STATUS_IMPORT_CHECK, buf);
+    m_free (buf);
+}
 
 /****************
  * Try to import one keyblock. Return an error only in serious cases, but
@@ -573,6 +549,7 @@ import_one( const char *fname, KBNODE keyblock,
     int rc = 0;
     int new_key = 0;
     int mod_key = 0;
+    int non_self = 0;
 
     /* get the key and print some info about it */
     node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
@@ -583,11 +560,7 @@ 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 ) {
+    if( opt.verbose && !opt.interactive ) {
        log_info( "pub  %4u%c/%08lX %s   ",
                  nbits_from_pk( pk ),
                  pubkey_letter( pk->pubkey_algo ),
@@ -603,6 +576,9 @@ import_one( const char *fname, KBNODE keyblock,
     }
     
     if (opt.interactive) {
+        if(is_status_enabled())
+         print_import_check (pk, uidnode->pkt->pkt.user_id);
+       merge_keys_and_selfsig (keyblock);
         tty_printf ("\n");
         show_basic_key_info (keyblock);
         tty_printf ("\n");
@@ -613,11 +589,12 @@ import_one( const char *fname, KBNODE keyblock,
 
     clear_kbnode_flags( keyblock );
 
-    if((options&IMPORT_REPAIR_HKP_SUBKEY_BUG) && fix_hkp_corruption(keyblock))
-      log_info(_("key %08lX: HKP subkey corruption repaired\n"),
+    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]);
 
-    rc = chk_self_sigs( fname, keyblock , pk, keyid );
+    rc = chk_self_sigs( fname, keyblock , pk, keyid, &non_self );
     if( rc )
        return rc== -1? 0:rc;
 
@@ -635,11 +612,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;
     }
@@ -651,12 +626,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);
 
@@ -680,7 +656,8 @@ import_one( const char *fname, KBNODE keyblock,
               be made to happen with the trusted-key command. */
 
            clear_ownertrusts (pk);
-           revalidation_mark ();
+           if(non_self)
+             revalidation_mark ();
          }
         keydb_release (hd);
 
@@ -757,7 +734,7 @@ import_one( const char *fname, KBNODE keyblock,
             if (rc)
                log_error (_("error writing keyring `%s': %s\n"),
                             keydb_get_resource_name (hd), g10_errstr(rc) );
-           else
+           else if(non_self)
              revalidation_mark ();
 
            /* we are ready */
@@ -928,27 +905,29 @@ 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)
          {
@@ -959,7 +938,7 @@ import_secret_one( const char *fname, KBNODE keyblock,
            release_kbnode(pub_keyblock);
          }
 
-    }
+      }
     else if( !rc ) { /* we can't merge secret keys */
        log_error( _("key %08lX: already in secret keyring\n"),
                                                        (ulong)keyid[1]);
@@ -1000,8 +979,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;
     }
@@ -1051,12 +1030,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 */
-       }
+         }
     }
 
 
@@ -1077,6 +1056,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:
@@ -1093,10 +1079,12 @@ import_revoke_cert( const char *fname, KBNODE node, struct stats_s *stats )
  * Mark all user-ids with an invalid self-signature by setting bit 1.
  * This works also for subkeys, here the subkey is marked.  Invalid or
  * extra subkey sigs (binding or revocation) are marked for deletion.
+ * non_self is set to true if there are any sigs other than self-sigs
+ * in this keyblock.
  */
 static int
 chk_self_sigs( const char *fname, KBNODE keyblock,
-              PKT_public_key *pk, u32 *keyid )
+              PKT_public_key *pk, u32 *keyid, int *non_self )
 {
     KBNODE n,knode=NULL;
     PKT_signature *sig;
@@ -1112,6 +1100,7 @@ chk_self_sigs( const char *fname, KBNODE keyblock,
          rsdate=0;
          bsnode=NULL;
          rsnode=NULL;
+         continue;
        }
       else if( n->pkt->pkttype != PKT_SIGNATURE )
            continue;
@@ -1136,15 +1125,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 */
@@ -1156,17 +1148,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 {
@@ -1177,8 +1171,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;
@@ -1197,18 +1192,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? */
@@ -1217,8 +1215,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;
@@ -1230,6 +1229,8 @@ chk_self_sigs( const char *fname, KBNODE keyblock,
                }
            }
        }
+       else
+         *non_self=1;
     }
 
     return 0;
@@ -1303,18 +1304,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 {
@@ -1329,9 +1330,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 );
                    }
                }
@@ -1341,11 +1343,20 @@ 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))
+         {
+           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 */
            delete_kbnode( node );
     }
@@ -1439,8 +1450,9 @@ 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;
 }
@@ -1555,23 +1567,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);
+                 }
            }
        }
     }
@@ -1600,8 +1614,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]);
            }
        }
     }
@@ -1769,20 +1784,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