Fix for bug 1223
authorWerner Koch <wk@gnupg.org>
Fri, 7 May 2010 12:32:06 +0000 (12:32 +0000)
committerWerner Koch <wk@gnupg.org>
Fri, 7 May 2010 12:32:06 +0000 (12:32 +0000)
g10/ChangeLog
g10/import.c

index 00b2bed..ccb6ae4 100644 (file)
@@ -1,3 +1,10 @@
+2010-05-07  Werner Koch  <wk@g10code.com>
+
+       * import.c (chk_self_sigs): Check direct key signatures.  Fixes
+       bug#1223.
+       (fix_bad_direct_key_sigs): New.
+       (import_one): Call it.
+
 2010-03-26  David Shaw  <dshaw@jabberwocky.com>
 
        * plaintext.c (handle_plaintext): Make sure that the stdout flush
index b179040..934101c 100644 (file)
@@ -516,6 +516,46 @@ fix_pks_corruption(KBNODE keyblock)
 }
 
 
+/* Versions of GnuPG before 1.4.11 and 2.0.16 allowed to import bogus
+   direct key signatures.  A side effect of this was that a later
+   import of the same good direct key signatures was not possible
+   because the cmp_signature check in merge_blocks considered them
+   equal.  Although direct key signatures are now checked during
+   import, there might still be bogus signatures sitting in a keyring.
+   We need to detect and delete them before doing a merge.  This
+   fucntion returns the number of removed sigs.  */
+static int
+fix_bad_direct_key_sigs (KBNODE keyblock, u32 *keyid)
+{
+  int rc;
+  int count = 0;
+  KBNODE node;
+
+  for (node = keyblock->next; node; node=node->next)
+    {
+      if (node->pkt->pkttype == PKT_USER_ID)
+        break;
+      if (node->pkt->pkttype == PKT_SIGNATURE
+          && IS_KEY_SIG (node->pkt->pkt.signature))
+        {
+          rc = check_key_signature (keyblock, node, NULL);
+          if (rc && rc != G10ERR_PUBKEY_ALGO )
+            {
+              /* If we don't know the error, we can't decide; this is
+                 not a problem because cmp_signature can't compare the
+                 signature either.  */
+              log_info ("key %s: invalid direct key signature removed\n",
+                        keystr (keyid));
+              delete_kbnode (node);
+              count++;
+            }
+        }
+    }
+
+  return count;
+}
+
+
 static void
 print_import_ok (PKT_public_key *pk, PKT_secret_key *sk, unsigned int reason)
 {
@@ -876,10 +916,15 @@ import_one( const char *fname, KBNODE keyblock, struct stats_s *stats,
            goto leave;
          }
 
+        /* Make sure the original direct key sigs are all sane.  */
+        n_sigs_cleaned = fix_bad_direct_key_sigs (keyblock_orig, keyid);
+        if (n_sigs_cleaned)
+          commit_kbnode (&keyblock_orig);
+            
        /* and try to merge the block */
        clear_kbnode_flags( keyblock_orig );
        clear_kbnode_flags( keyblock );
-       n_uids = n_sigs = n_subk = n_sigs_cleaned = n_uids_cleaned = 0;
+       n_uids = n_sigs = n_subk = n_uids_cleaned = 0;
        rc = merge_blocks( fname, keyblock_orig, keyblock,
                           keyid, &n_uids, &n_sigs, &n_subk );
        if( rc )
@@ -1397,6 +1442,19 @@ chk_self_sigs( const char *fname, KBNODE keyblock,
                    unode->flag |= 1; /* mark that signature checked */
                }
              }
+            else if (IS_KEY_SIG (sig))
+              {
+                rc = check_key_signature (keyblock, n, NULL);
+                if ( rc )
+                  {
+                    if (opt.verbose)
+                      log_info (rc == G10ERR_PUBKEY_ALGO ?
+                                _("key %s: unsupported public key algorithm\n"):
+                                _("key %s: invalid direct key signature\n"),
+                                keystr (keyid));
+                    n->flag |= 4;
+                  }
+              }
            else if( sig->sig_class == 0x18 ) {
              /* Note that this works based solely on the timestamps
                 like the rest of gpg.  If the standard gets