gpg locks up with certain key servers

David Shaw dshaw at jabberwocky.com
Sun Aug 12 01:57:58 CEST 2007


On Fri, Aug 10, 2007 at 12:29:05AM -0400, David Shaw wrote:

> GPG isn't actually locking up here - it's just very slow.  The
> reason for the slow import of that key is the need for GPG to detect
> and remove the duplicated packets.  On my machine, it takes just
> under an hour to process that key.
> 
> The algorithm currently in GPG for detecting and repairing the
> duplication is not as efficient as it could be.  I'll have a look at
> it and see what I can do.

Try this patch.  It can import the corrupt key in around 5 seconds on
my machine.

David
-------------- next part --------------
Index: import.c
===================================================================
--- import.c	(revision 4557)
+++ import.c	(working copy)
@@ -1644,11 +1644,108 @@
  * It may happen that the imported keyblock has duplicated user IDs.
  * We check this here and collapse those user IDs together with their
  * sigs into one.
- * Returns: True if the keyblock hash changed.
+ * Returns: True if the keyblock has changed.
  */
 int
 collapse_uids( KBNODE *keyblock )
 {
+  KBNODE uid1;
+  int any=0;
+
+  for(uid1=*keyblock;uid1;uid1=uid1->next)
+    {
+      KBNODE uid2;
+
+      if(uid1->pkt->pkttype!=PKT_USER_ID)
+	continue;
+
+      for(uid2=uid1->next;uid2;uid2=uid2->next)
+	{
+	  if(uid2->pkt->pkttype!=PKT_USER_ID)
+	    continue;
+
+	  if(cmp_user_ids(uid1->pkt->pkt.user_id,
+			  uid2->pkt->pkt.user_id)==0)
+	    {
+	      /* We have a duplicated uid */
+	      KBNODE sig1,last;
+
+	      any=1;
+
+	      /* Now take uid2's signatures, and attach them to
+		 uid1 */
+	      for(last=uid2;last->next;last=last->next)
+		{
+		  if(last->next->pkt->pkttype==PKT_USER_ID
+		     || last->next->pkt->pkttype==PKT_PUBLIC_SUBKEY
+		     || last->next->pkt->pkttype==PKT_SECRET_SUBKEY)
+		    break;
+		}
+
+	      /* Snip out uid2 */
+	      (find_prev_kbnode(*keyblock,uid2,0))->next=last->next;
+
+	      /* Now put uid2 in place as part of uid1 */
+	      last->next=uid1->next;
+	      uid1->next=uid2;
+	      remove_kbnode(keyblock,uid2);
+
+	      /* Now dedupe uid1 */
+	      for(sig1=uid1->next;sig1;sig1=sig1->next)
+		{
+		  KBNODE sig2;
+
+		  if(sig1->pkt->pkttype==PKT_USER_ID
+		     || sig1->pkt->pkttype==PKT_PUBLIC_SUBKEY
+		     || sig1->pkt->pkttype==PKT_SECRET_SUBKEY)
+		    break;
+
+		  if(sig1->pkt->pkttype!=PKT_SIGNATURE)
+		    continue;
+
+		  for(sig2=sig1->next,last=sig1;sig2;last=sig2,sig2=sig2->next)
+		    {
+		      if(sig2->pkt->pkttype==PKT_USER_ID
+			 || sig2->pkt->pkttype==PKT_PUBLIC_SUBKEY
+			 || sig2->pkt->pkttype==PKT_SECRET_SUBKEY)
+			break;
+
+		      if(sig2->pkt->pkttype!=PKT_SIGNATURE)
+			continue;
+
+		      if(cmp_signatures(sig1->pkt->pkt.signature,
+					sig2->pkt->pkt.signature)==0)
+			{
+			  /* We have a match, so delete the second
+			     signature */
+			  remove_kbnode(&uid1,sig2);
+			  sig2=last;
+			}
+		    }
+		}
+	    }
+	}
+    }
+
+  if(any && !opt.quiet)
+    {
+      const char *key="???";
+
+      if( (uid1=find_kbnode( *keyblock, PKT_PUBLIC_KEY )) )
+	key=keystr_from_pk(uid1->pkt->pkt.public_key);
+      else if( (uid1 = find_kbnode( *keyblock, PKT_SECRET_KEY )) )
+	key=keystr_from_sk(uid1->pkt->pkt.secret_key);
+
+      log_info(_("key %s: duplicated user ID detected - merged\n"),key);
+    }
+
+  return any;
+}
+
+#if 0
+int
+collapse_uids( KBNODE *keyblock )
+{
     KBNODE n, n2;
     int in_uid;
     int any=0;
@@ -1729,6 +1826,7 @@
 
     return 1;
 }
+#endif
 
 /* Check for a 0x20 revocation from a revocation key that is not
    present.  This may be called without the benefit of merge_xxxx so


More information about the Gnupg-devel mailing list