commit 3a403ab04eeb45f12b34f9d9c421dac93eaf2160
Author: Werner Koch <wk@gnupg.org>
Date:   Mon Jul 1 21:53:55 2019 +0200

    gpg: Fallback to import with self-sigs-only on too large keyblocks.
    
    * g10/import.c (import_one): Rename to ...
    (import_one_real): this.  Do not print and update stats on keyring
    write errors.
    (import_one): New.  Add fallback code.
    --
    
    GnuPG-bug-id: 4591
    Signed-off-by: Werner Koch <wk@gnupg.org>

Index: gnupg-2.0.9/g10/import.c
===================================================================
--- gnupg-2.0.9.orig/g10/import.c
+++ gnupg-2.0.9/g10/import.c
@@ -74,6 +74,7 @@ static int chk_self_sigs( const char *fn
 			  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 void remove_all_non_self_sigs (KBNODE *keyblock, u32 *keyid);
 static int merge_blocks( const char *fname, KBNODE keyblock_orig,
 			 KBNODE keyblock, u32 *keyid,
 			 int *n_uids, int *n_sigs, int *n_subk );
@@ -745,8 +746,8 @@ check_prefs(KBNODE keyblock)
  * internal errorcount, so that invalid input can be detected by programs
  * which called g10.
  */
-static int
-import_one( const char *fname, KBNODE keyblock, struct stats_s *stats,
+static gpg_error_t
+import_one_real (const char *fname, KBNODE keyblock, struct stats_s *stats,
 	    unsigned char **fpr,size_t *fpr_len,unsigned int options,
 	    int from_sk )
 {
@@ -800,6 +801,13 @@ import_one( const char *fname, KBNODE ke
             return 0;
     }
 
+    /* Remove all non-self-sigs if requested.  Noe that this is a NOP if
+     * that option has been globally set but we may also be called
+     * latter with the already parsed keyblock and a locally changed
+     * option.  This is why we need to remove them here as well.  */
+    if ((options & IMPORT_SELF_SIGS_ONLY))
+      remove_all_non_self_sigs (&keyblock, keyid);
+
     collapse_uids(&keyblock);
 
     /* Clean the key that we're about to import, to cut down on things
@@ -970,8 +978,10 @@ import_one( const char *fname, KBNODE ke
 	    else if(non_self)
 	      revalidation_mark ();
 
-	    /* we are ready */
-	    if( !opt.quiet )
+	    /* we are ready. Print and update stats if we got no error.
+	     * An error here comes from writing the keyblock and thus
+	     * very likely means that no update happened.  */
+	    if (!opt.quiet)
 	      {
 	        char *p=get_user_id_native(keyid);
 		if( n_uids == 1 )
@@ -1078,6 +1088,38 @@ import_one( const char *fname, KBNODE ke
     return rc;
 }
 
+
+/* Wrapper around import_one_real to retry the import in some cases.  */
+static int
+import_one (const char *fname, KBNODE keyblock, struct stats_s *stats,
+	    unsigned char **fpr, size_t *fpr_len, unsigned int options,
+	    int from_sk)
+{
+  gpg_error_t err;
+
+  err = import_one_real (fname, keyblock, stats, fpr, fpr_len, options,
+			 from_sk);
+  if (gpg_err_code (err) == GPG_ERR_TOO_LARGE
+      && gpg_err_source (err) == GPG_ERR_SOURCE_KEYBOX
+      && ((options & (IMPORT_SELF_SIGS_ONLY | IMPORT_CLEAN))
+          != (IMPORT_SELF_SIGS_ONLY | IMPORT_CLEAN)))
+    {
+      /* We hit the maximum image length.  Ask the wrapper to do
+       * everything again but this time with some extra options.  */
+      u32 keyid[2];
+
+      keyid_from_pk (keyblock->pkt->pkt.public_key, keyid);
+      log_info ("key %s: keyblock too large, retrying with self-sigs-only\n",
+                keystr (keyid));
+      options |= IMPORT_SELF_SIGS_ONLY | IMPORT_CLEAN;
+      err = import_one_real (fname, keyblock, stats, fpr, fpr_len, options,
+			     from_sk);
+
+    }
+  return err;
+}
+
+
 /* Walk a secret keyblock and produce a public keyblock out of it. */
 static KBNODE
 sec_to_pub_keyblock(KBNODE sec_keyblock)
@@ -1394,6 +1436,38 @@ import_revoke_cert( const char *fname, K
 }
 
 
+/* Delete all non-self-sigs from KEYBLOCK.
+ * Returns: True if the keyblock has changed.  */
+static void
+remove_all_non_self_sigs (KBNODE *keyblock, u32 *keyid)
+{
+  KBNODE node;
+  unsigned int dropped = 0;
+
+  for (node = *keyblock; node; node = node->next)
+    {
+      if (is_deleted_kbnode (node))
+	continue;
+
+      if (node->pkt->pkttype != PKT_SIGNATURE)
+	continue;
+
+      if (node->pkt->pkt.signature->keyid[0] == keyid[0]
+          && node->pkt->pkt.signature->keyid[1] == keyid[1])
+        continue;
+      delete_kbnode (node);
+      dropped++;
+    }
+
+  if (dropped)
+    commit_kbnode (keyblock);
+
+  if (dropped && opt.verbose)
+    log_info ("key %s: number of dropped non-self-signatures: %u\n",
+              keystr (keyid), dropped);
+}
+
+
 /****************
  * loop over the keyblock and check all self signatures.
  * Mark all user-ids with a self-signature by setting flag bit 0.
