* gpgv.c: Remove extra semicolon (typo).
[gnupg.git] / g10 / import.c
index 4060bdf..8d94c39 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.
  *
@@ -56,19 +57,18 @@ struct stats_s {
 };
 
 
-static int import( IOBUF inp, int fast, const char* fname,
+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, int fast,
+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,
-                              struct stats_s *stats );
+                              struct stats_s *stats, unsigned int options);
 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,
@@ -83,51 +83,20 @@ static int merge_sigs( KBNODE dst, KBNODE src, int *n_sigs,
 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)
 {
-  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},
       {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);
 }
 
 void *
@@ -173,64 +142,78 @@ import_release_stats_handle (void *p)
  *  Key revocation certificates have special handling.
  *
  */
-void
-import_keys( char **fnames, int nnames, int fast,
-            void *stats_handle, unsigned int options )
+static int
+import_keys_internal( IOBUF inp, char **fnames, int nnames,
+                     void *stats_handle, unsigned int options )
 {
-    int i;
+    int i, rc = 0;
     struct stats_s *stats = stats_handle;
 
     if (!stats)
         stats = import_new_stats_handle ();
 
-    if( !fnames && !nnames )
-       nnames = 1;  /* Ohh what a ugly hack to jump into the loop */
-
-    for(i=0; i < nnames; i++ ) {
-       const char *fname = fnames? fnames[i] : NULL;
-       IOBUF inp = iobuf_open(fname);
-       if( !fname )
-           fname = "[stdin]";
-       if( !inp )
-           log_error(_("can't open `%s': %s\n"), fname, strerror(errno) );
-       else {
-           int rc = import( inp, fast, fname, stats, options );
-           iobuf_close(inp);
-           if( rc )
-               log_error("import from `%s' failed: %s\n", fname,
-                                                          g10_errstr(rc) );
+    if (inp) {
+        rc = import( inp, "[stream]", stats, options);
+    }
+    else {
+        if( !fnames && !nnames )
+           nnames = 1;  /* Ohh what a ugly hack to jump into the loop */
+
+       for(i=0; i < nnames; i++ ) {
+           const char *fname = fnames? fnames[i] : NULL;
+           IOBUF inp2 = iobuf_open(fname);
+           if( !fname )
+               fname = "[stdin]";
+           if( !inp2 )
+               log_error(_("can't open `%s': %s\n"), fname, strerror(errno) );
+           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) );
+           }
+           if( !fname )
+               break;
        }
-       if( !fname )
-           break;
     }
     if (!stats_handle) {
         import_print_stats (stats);
         import_release_stats_handle (stats);
     }
+    /* 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();
+      }
 
+    return rc;
 }
 
-int
-import_keys_stream( IOBUF inp, int fast,
-                   void *stats_handle, unsigned int options )
+void
+import_keys( char **fnames, int nnames,
+            void *stats_handle, unsigned int options )
 {
-    int rc = 0;
-    struct stats_s *stats = stats_handle;
-
-    if (!stats)
-        stats = import_new_stats_handle ();
-
-    rc = import( inp, fast, "[stream]", stats, options);
-    if (!stats_handle) {
-        import_print_stats (stats);
-        import_release_stats_handle (stats);
-    }
+    import_keys_internal( NULL, fnames, nnames, stats_handle, options);
+}
 
-    return rc;
+int
+import_keys_stream( IOBUF inp, void *stats_handle, unsigned int options )
+{
+    return import_keys_internal( inp, NULL, 0, stats_handle, options);
 }
 
 static int
-import( IOBUF inp, int fast, const char* fname,
+import( IOBUF inp, const char* fname,
        struct stats_s *stats, unsigned int options )
 {
     PACKET *pending_pkt = NULL;
@@ -246,11 +229,10 @@ import( IOBUF inp, int fast, 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, fast, stats, options );
+           rc = import_one( fname, keyblock, stats, options );
        else if( keyblock->pkt->pkttype == PKT_SECRET_KEY ) 
-                rc = import_secret_one( fname, keyblock, stats );
+                rc = import_secret_one( fname, keyblock, stats, options );
        else if( keyblock->pkt->pkttype == PKT_SIGNATURE
                 && keyblock->pkt->pkt.signature->sig_class == 0x20 )
            rc = import_revoke_cert( fname, keyblock, stats );
@@ -264,7 +246,7 @@ import( IOBUF inp, int fast, const char* fname,
        if( rc )
            break;
        if( !(++stats->count % 100) && !opt.quiet )
-           log_info(_("%lu keys so far processed\n"), stats->count );
+           log_info(_("%lu keys processed so far\n"), stats->count );
     }
     if( rc == -1 )
        rc = 0;
@@ -436,23 +418,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
@@ -462,7 +428,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;
@@ -493,6 +459,10 @@ fix_hkp_corruption(KBNODE keyblock)
          sknode->next=node;
          last->next=NULL;
 
+         /* Note we aren't checking whether this binding sig is a
+            selfsig.  This is not necessary here as the subkey and
+            binding sig will be rejected later if that is the
+            case. */
          if(check_key_signature(keyblock,node,NULL))
            {
              /* Not a match, so undo the changes. */
@@ -538,6 +508,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
@@ -546,7 +537,7 @@ print_import_ok (PKT_public_key *pk, PKT_secret_key *sk, unsigned int reason)
  * which called g10.
  */
 static int
-import_one( const char *fname, KBNODE keyblock, int fast,
+import_one( const char *fname, KBNODE keyblock,
             struct stats_s *stats, unsigned int options )
 {
     PKT_public_key *pk;
@@ -557,6 +548,7 @@ import_one( const char *fname, KBNODE keyblock, int fast,
     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 );
@@ -567,7 +559,11 @@ import_one( const char *fname, KBNODE keyblock, int fast,
     keyid_from_pk( pk, keyid );
     uidnode = find_next_kbnode( keyblock, PKT_USER_ID );
 
-    if( opt.verbose ) {
+    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 ),
                  pubkey_letter( pk->pubkey_algo ),
@@ -583,6 +579,9 @@ import_one( const char *fname, KBNODE keyblock, int fast,
     }
     
     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");
@@ -593,11 +592,12 @@ import_one( const char *fname, KBNODE keyblock, int fast,
 
     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;
 
@@ -615,18 +615,16 @@ import_one( const char *fname, KBNODE keyblock, int fast,
          }
 
     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;
     }
 
     /* do we have this key already in one of our pubrings ? */
     pk_orig = m_alloc_clear( sizeof *pk_orig );
-    rc = get_pubkey( pk_orig, keyid );
+    rc = get_pubkey_fast ( pk_orig, keyid );
     if( rc && rc != G10ERR_NO_PUBKEY && rc != G10ERR_UNU_PUBKEY ) {
        log_error( _("key %08lX: public key not found: %s\n"),
                                (ulong)keyid[1], g10_errstr(rc));
@@ -635,7 +633,6 @@ import_one( const char *fname, KBNODE keyblock, int fast,
        if( opt.verbose )
            log_info( _("key %08lX: new key - skipped\n"), (ulong)keyid[1] );
        rc = 0;
-       fast = 1; /* so that we don't get into the trustdb update */
        stats->skipped_new_keys++;
     }
     else if( rc ) { /* insert this key */
@@ -654,7 +651,16 @@ import_one( const char *fname, KBNODE keyblock, int fast,
           log_error (_("error writing keyring `%s': %s\n"),
                       keydb_get_resource_name (hd), g10_errstr(rc));
        else
-          revalidation_mark ();
+         {
+           /* This should not be possible since we delete the
+              ownertrust when a key is deleted, but it can happen if
+              the keyring and trustdb are out of sync.  It can also
+              be made to happen with the trusted-key command. */
+
+           clear_ownertrusts (pk);
+           if(non_self)
+             revalidation_mark ();
+         }
         keydb_release (hd);
 
        /* we are ready */
@@ -730,7 +736,7 @@ import_one( const char *fname, KBNODE keyblock, int fast,
             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 */
@@ -789,6 +795,65 @@ import_one( const char *fname, KBNODE keyblock, int fast,
     return rc;
 }
 
+/* Walk a secret keyblock and produce a public keyblock out of it. */
+static KBNODE
+sec_to_pub_keyblock(KBNODE sec_keyblock)
+{
+  KBNODE secnode,pub_keyblock=NULL,ctx=NULL;
+
+  while((secnode=walk_kbnode(sec_keyblock,&ctx,0)))
+    {
+      KBNODE pubnode;
+
+      if(secnode->pkt->pkttype==PKT_SECRET_KEY ||
+        secnode->pkt->pkttype==PKT_SECRET_SUBKEY)
+       {
+         /* Make a public key.  We only need to convert enough to
+            write the keyblock out. */
+
+         PKT_secret_key *sk=secnode->pkt->pkt.secret_key;
+         PACKET *pkt=m_alloc_clear(sizeof(PACKET));
+         PKT_public_key *pk=m_alloc_clear(sizeof(PKT_public_key));
+         int n;
+
+         if(secnode->pkt->pkttype==PKT_SECRET_KEY)
+           pkt->pkttype=PKT_PUBLIC_KEY;
+         else
+           pkt->pkttype=PKT_PUBLIC_SUBKEY;
+
+         pkt->pkt.public_key=pk;
+
+         pk->version=sk->version;
+         pk->timestamp=sk->timestamp;
+         pk->expiredate=sk->expiredate;
+         pk->pubkey_algo=sk->pubkey_algo;
+
+         n=pubkey_get_npkey(pk->pubkey_algo);
+         if(n==0)
+           pk->pkey[0]=mpi_copy(sk->skey[0]);
+         else
+           {
+             int i;
+
+             for(i=0;i<n;i++)
+               pk->pkey[i]=mpi_copy(sk->skey[i]);
+           }
+
+         pubnode=new_kbnode(pkt);
+       }
+      else
+       {
+         pubnode=clone_kbnode(secnode);
+       }
+
+      if(pub_keyblock==NULL)
+       pub_keyblock=pubnode;
+      else
+       add_kbnode(pub_keyblock,pubnode);
+    }
+
+  return pub_keyblock;
+}
 
 /****************
  * Ditto for secret keys.  Handling is simpler than for public keys.
@@ -798,7 +863,7 @@ import_one( const char *fname, KBNODE keyblock, int fast,
  */
 static int
 import_secret_one( const char *fname, KBNODE keyblock, 
-                   struct stats_s *stats)
+                   struct stats_s *stats, unsigned int options)
 {
     PKT_secret_key *sk;
     KBNODE node, uidnode;
@@ -831,6 +896,13 @@ import_secret_one( const char *fname, KBNODE keyblock,
        return 0;
     }
 
+    if(sk->protect.algo>110)
+      {
+       log_error(_("key %08lX: secret key with invalid cipher %d "
+                   "- skipped\n"),(ulong)keyid[1],sk->protect.algo);
+       return 0;
+      }
+
     clear_kbnode_flags( keyblock );
 
     /* do we have this key already in one of our secrings ? */
@@ -856,6 +928,16 @@ import_secret_one( const char *fname, KBNODE keyblock,
        stats->secret_imported++;
         if (is_status_enabled ()) 
              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);
+         }
+
     }
     else if( !rc ) { /* we can't merge secret keys */
        log_error( _("key %08lX: already in secret keyring\n"),
@@ -863,6 +945,9 @@ import_secret_one( const char *fname, KBNODE keyblock,
        stats->secret_dups++;
         if (is_status_enabled ()) 
              print_import_ok (NULL, sk, 16);
+
+       /* TODO: if we ever do merge secret keys, make sure to handle
+          the sec_to_pub_keyblock feature as well. */
     }
     else
        log_error( _("key %08lX: secret key not found: %s\n"),
@@ -894,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;
     }
@@ -945,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 */
-       }
+         }
     }
 
 
@@ -971,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:
@@ -987,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;
@@ -1006,11 +1100,18 @@ chk_self_sigs( const char *fname, KBNODE keyblock,
          rsdate=0;
          bsnode=NULL;
          rsnode=NULL;
+         continue;
        }
       else if( n->pkt->pkttype != PKT_SIGNATURE )
            continue;
        sig = n->pkt->pkt.signature;
        if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] ) {
+
+         /* This just caches the sigs for later use.  That way we
+            import a fully-cached key which speeds things up. */
+         if(!opt.no_sig_cache)
+           check_key_signature(keyblock,n,NULL);
+
            if( (sig->sig_class&~3) == 0x10 ) {
                KBNODE unode = find_prev_kbnode( keyblock, n, PKT_USER_ID );
                if( !unode )  {
@@ -1024,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 */
@@ -1044,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 key binding\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 {
@@ -1065,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;
@@ -1085,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 key revocation\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? */
@@ -1105,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\n"),(ulong)keyid[1]);
+                       if(opt.verbose)
+                         log_info(_("key %08lX: removed multiple subkey "
+                                    "revocation\n"),(ulong)keyid[1]);
                      }
 
                      rsnode=n;
@@ -1118,6 +1229,8 @@ chk_self_sigs( const char *fname, KBNODE keyblock,
                }
            }
        }
+       else
+         *non_self=1;
     }
 
     return 0;
@@ -1191,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 {
@@ -1217,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 );
                    }
                }
@@ -1229,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 );
     }
@@ -1327,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;
 }
@@ -1378,8 +1502,8 @@ revocation_present(KBNODE keyblock)
                          itself? */
                      int rc;
 
-                     rc=get_pubkey_byfprint(NULL,sig->revkey[idx]->fpr,
-                                            MAX_FINGERPRINT_LEN);
+                     rc=get_pubkey_byfprint_fast (NULL,sig->revkey[idx]->fpr,
+                                                   MAX_FINGERPRINT_LEN);
                      if(rc==G10ERR_NO_PUBKEY || rc==G10ERR_UNU_PUBKEY)
                        {
                          /* No, so try and get it */
@@ -1394,7 +1518,7 @@ revocation_present(KBNODE keyblock)
                                                      MAX_FINGERPRINT_LEN);
 
                              /* Do we have it now? */
-                             rc=get_pubkey_byfprint(NULL,
+                             rc=get_pubkey_byfprint_fast (NULL,
                                                     sig->revkey[idx]->fpr,
                                                     MAX_FINGERPRINT_LEN);
                            }
@@ -1443,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);
+                 }
            }
        }
     }
@@ -1488,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]);
            }
        }
     }
@@ -1657,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