* main.h, import.c (parse_import_options, fix_hkp_corruption, import_one,
authorDavid Shaw <dshaw@jabberwocky.com>
Wed, 24 Jul 2002 21:17:19 +0000 (21:17 +0000)
committerDavid Shaw <dshaw@jabberwocky.com>
Wed, 24 Jul 2002 21:17:19 +0000 (21:17 +0000)
delete_inv_parts), g10.c (main): New import-option
"repair-hkp-subkey-bug", which repairs as much as possible the HKP
mangling multiple subkeys bug.  It is on by default for keyserver
receives, and off by default for regular --import.

* main.h, import.c (import, import_one, delete_inv_parts), hkp.c
(hkp_ask_import), keyserver.c (keyserver_spawn): Use keyserver import
options when doing keyserver receives.

g10/ChangeLog
g10/g10.c
g10/hkp.c
g10/import.c
g10/keyserver.c
g10/main.h

index 02de71b..8478edc 100644 (file)
@@ -1,5 +1,15 @@
 2002-07-24  David Shaw  <dshaw@jabberwocky.com>
 
+       * main.h, import.c (parse_import_options, fix_hkp_corruption,
+       import_one, delete_inv_parts), g10.c (main): New import-option
+       "repair-hkp-subkey-bug", which repairs as much as possible the HKP
+       mangling multiple subkeys bug.  It is on by default for keyserver
+       receives, and off by default for regular --import.
+
+       * main.h, import.c (import, import_one, delete_inv_parts), hkp.c
+       (hkp_ask_import), keyserver.c (keyserver_spawn): Use keyserver
+       import options when doing keyserver receives.
+
        * options.h, exec.h, exec.c (set_exec_path, exec_write), g10.c
        (main), keyserver.c (keyserver_spawn): If the user does not use
        "exec-path", completely replace $PATH with GNUPG_LIBEXECDIR before
index 7a1b624..fc50781 100644 (file)
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -906,10 +906,12 @@ main( int argc, char **argv )
     opt.pgp2_workarounds = 1;
     opt.force_v3_sigs = 1;
     opt.escape_from = 1;
-    opt.import_options=IMPORT_DEFAULT;
-    opt.export_options=EXPORT_DEFAULT;
-    opt.keyserver_options.import_options=IMPORT_DEFAULT;
-    opt.keyserver_options.export_options=EXPORT_DEFAULT;
+    opt.import_options=0;
+    opt.export_options=
+      EXPORT_INCLUDE_NON_RFC|EXPORT_INCLUDE_ATTRIBUTES;
+    opt.keyserver_options.import_options=IMPORT_REPAIR_HKP_SUBKEY_BUG;
+    opt.keyserver_options.export_options=
+      EXPORT_INCLUDE_NON_RFC|EXPORT_INCLUDE_ATTRIBUTES;
     opt.keyserver_options.include_subkeys=1;
 #if defined (__MINGW32__) || defined (__CYGWIN32__)
     opt.homedir = read_w32_registry_string( NULL, "Software\\GNU\\GnuPG", "HomeDir" );
@@ -2027,7 +2029,8 @@ main( int argc, char **argv )
 
       case aFastImport:
       case aImport:
-       import_keys( argc? argv:NULL, argc, (cmd == aFastImport), NULL );
+       import_keys( argc? argv:NULL, argc, (cmd == aFastImport),
+                    NULL, opt.import_options );
        break;
 
       case aExport:
index 09fa5a1..234a578 100644 (file)
--- a/g10/hkp.c
+++ b/g10/hkp.c
@@ -98,7 +98,8 @@ hkp_ask_import( KEYDB_SEARCH_DESC *desc, void *stats_handle)
                                            : g10_errstr(rc) );
     }
     else {
-      rc = import_keys_stream( hd.fp_read, 0, stats_handle);
+      rc = import_keys_stream( hd.fp_read, 0, stats_handle,
+                              opt.keyserver_options.import_options);
        http_close( &hd );
     }
 
index 415e26e..4be313f 100644 (file)
@@ -55,19 +55,20 @@ struct stats_s {
 
 
 static int import( IOBUF inp, int fast, const char* fname,
-                   struct stats_s *stats );
+                   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,
-                       struct stats_s *stats);
+                       struct stats_s *stats, unsigned int options);
 static int import_secret_one( const char *fname, KBNODE keyblock,
                               struct stats_s *stats );
 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 );
-static int delete_inv_parts( const char *fname, KBNODE keyblock, u32 *keyid );
+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,
                         KBNODE keyblock, u32 *keyid,
                         int *n_uids, int *n_sigs, int *n_subk );
@@ -93,6 +94,7 @@ parse_import_options(char *str,unsigned int *options)
   } import_opts[]=
     {
       {"allow-local-sigs",IMPORT_ALLOW_LOCAL_SIGS},
+      {"repair-hkp-subkey-bug",IMPORT_REPAIR_HKP_SUBKEY_BUG},
       {NULL,0}
     };
 
@@ -170,7 +172,8 @@ import_release_stats_handle (void *p)
  *
  */
 void
-import_keys( char **fnames, int nnames, int fast, void *stats_handle )
+import_keys( char **fnames, int nnames, int fast,
+            void *stats_handle, unsigned int options )
 {
     int i;
     struct stats_s *stats = stats_handle;
@@ -189,7 +192,7 @@ import_keys( char **fnames, int nnames, int fast, void *stats_handle )
        if( !inp )
            log_error(_("can't open `%s': %s\n"), fname, strerror(errno) );
        else {
-           int rc = import( inp, fast, fname, stats );
+           int rc = import( inp, fast, fname, stats, options );
            iobuf_close(inp);
            if( rc )
                log_error("import from `%s' failed: %s\n", fname,
@@ -206,7 +209,8 @@ import_keys( char **fnames, int nnames, int fast, void *stats_handle )
 }
 
 int
-import_keys_stream( IOBUF inp, int fast, void *stats_handle )
+import_keys_stream( IOBUF inp, int fast,
+                   void *stats_handle, unsigned int options )
 {
     int rc = 0;
     struct stats_s *stats = stats_handle;
@@ -214,7 +218,7 @@ import_keys_stream( IOBUF inp, int fast, void *stats_handle )
     if (!stats)
         stats = import_new_stats_handle ();
 
-    rc = import( inp, fast, "[stream]", stats);
+    rc = import( inp, fast, "[stream]", stats, options);
     if (!stats_handle) {
         import_print_stats (stats);
         import_release_stats_handle (stats);
@@ -224,7 +228,8 @@ import_keys_stream( IOBUF inp, int fast, void *stats_handle )
 }
 
 static int
-import( IOBUF inp, int fast, const char* fname, struct stats_s *stats )
+import( IOBUF inp, int fast, const char* fname,
+       struct stats_s *stats, unsigned int options )
 {
     PACKET *pending_pkt = NULL;
     KBNODE keyblock;
@@ -241,7 +246,7 @@ import( IOBUF inp, int fast, const char* fname, struct stats_s *stats )
     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 );
+           rc = import_one( fname, keyblock, fast, stats, options );
        else if( keyblock->pkt->pkttype == PKT_SECRET_KEY ) 
                 rc = import_secret_one( fname, keyblock, stats );
        else if( keyblock->pkt->pkttype == PKT_SIGNATURE
@@ -440,6 +445,70 @@ remove_bad_stuff (KBNODE keyblock)
     }
 }
 
+/* Walk through the subkeys on a pk to find if we have the HKP
+   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
+   "pk uid sig sub1 sub2 sub3 bind1".  We can't do anything about sub2
+   and sub3, as they are already lost, but we can try and rescue sub1
+   by reordering the keyblock so that it reads "pk uid sig sub1 bind1
+   sub2 sub3".  Returns TRUE if the keyblock was modified. */
+
+static int
+fix_hkp_corruption(KBNODE keyblock)
+{
+  int changed=0,keycount=0;
+  KBNODE node,last=NULL,sknode=NULL;
+
+  /* First determine if we have the problem at all.  Look for 2 or
+     more subkeys in a row, followed by a single binding sig. */
+  for(node=keyblock;node;last=node,node=node->next)
+    {
+      if(node->pkt->pkttype==PKT_PUBLIC_SUBKEY)
+       {
+         keycount++;
+         if(!sknode)
+           sknode=node;
+       }
+      else if(node->pkt->pkttype==PKT_SIGNATURE &&
+             node->pkt->pkt.signature->sig_class==0x18 &&
+             keycount>=2 && node->next==NULL)
+       {
+         /* We might have the problem, as this key has two subkeys in
+            a row without any intervening packets. */
+
+         /* Sanity check */
+         if(last==NULL)
+           break;
+
+         /* Temporarily attach node to sknode. */
+         node->next=sknode->next;
+         sknode->next=node;
+         last->next=NULL;
+
+         if(check_key_signature(keyblock,node,NULL))
+           {
+             /* Not a match, so undo the changes. */
+             sknode->next=node->next;
+             last->next=node;
+             node->next=NULL;
+             break;
+           }
+         else
+           {
+             sknode->flag |= 1; /* Mark it good so we don't need to
+                                    check it again */
+             changed=1;
+             break;
+           }
+       }
+      else
+       keycount=0;
+    }
+
+  return changed;
+}
+
 /* Clean the subkeys on a pk so that they each have at most 1 binding
    sig and at most 1 revocation sig.  This works based solely on the
    timestamps like the rest of gpg.  If the standard does get
@@ -538,7 +607,7 @@ clean_subkeys(KBNODE keyblock,u32 *keyid)
  */
 static int
 import_one( const char *fname, KBNODE keyblock, int fast,
-            struct stats_s *stats )
+            struct stats_s *stats, unsigned int options )
 {
     PKT_public_key *pk;
     PKT_public_key *pk_orig;
@@ -574,6 +643,11 @@ 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"),
+              (ulong)keyid[1]);
+
     rc = chk_self_sigs( fname, keyblock , pk, keyid );
     if( rc )
        return rc== -1? 0:rc;
@@ -591,7 +665,7 @@ import_one( const char *fname, KBNODE keyblock, int fast,
            m_free(user);
          }
 
-    if( !delete_inv_parts( fname, keyblock, keyid ) ) {
+    if( !delete_inv_parts( fname, keyblock, keyid, options ) ) {
        if( !opt.quiet ) {
            log_info( _("key %08lX: no valid user IDs\n"),
                                                        (ulong)keyid[1]);
@@ -1033,7 +1107,8 @@ chk_self_sigs( const char *fname, KBNODE keyblock,
  * returns: true if at least one valid user-id is left over.
  */
 static int
-delete_inv_parts( const char *fname, KBNODE keyblock, u32 *keyid )
+delete_inv_parts( const char *fname, KBNODE keyblock,
+                 u32 *keyid, unsigned int options)
 {
     KBNODE node;
     int nvalid=0, uid_seen=0, subkey_seen=0;
@@ -1086,7 +1161,7 @@ delete_inv_parts( const char *fname, KBNODE keyblock, u32 *keyid )
            delete_kbnode( node ); /* build_packet() can't handle this */
        else if( node->pkt->pkttype == PKT_SIGNATURE &&
                 !node->pkt->pkt.signature->flags.exportable &&
-                !(opt.import_options&IMPORT_ALLOW_LOCAL_SIGS) &&
+                !(options&IMPORT_ALLOW_LOCAL_SIGS) &&
                 seckey_available( node->pkt->pkt.signature->keyid ) ) {
            /* here we violate the rfc a bit by still allowing
             * to import non-exportable signature when we have the
index c64ad4b..97745f0 100644 (file)
@@ -598,7 +598,8 @@ keyserver_spawn(int action,STRLIST list,
             do this could be to continue parsing this line-by-line and
             make a temp iobuf for each key. */
 
-         import_keys_stream(spawn->fromchild,0,stats_handle);
+         import_keys_stream(spawn->fromchild,0,stats_handle,
+                            opt.keyserver_options.import_options);
 
          import_print_stats(stats_handle);
          import_release_stats_handle(stats_handle);
index 05da9c8..9edccaf 100644 (file)
@@ -150,13 +150,14 @@ KBNODE make_comment_node( const char *s );
 KBNODE make_mpi_comment_node( const char *s, MPI a );
 
 /*-- import.c --*/
-/* 1, 4, and 8 are reserved so they match the EXPORT_* flags below */
-#define IMPORT_ALLOW_LOCAL_SIGS 2
-#define IMPORT_DEFAULT          0
+#define IMPORT_ALLOW_LOCAL_SIGS      1
+#define IMPORT_REPAIR_HKP_SUBKEY_BUG 2
 
 int parse_import_options(char *str,unsigned int *options);
-void import_keys( char **fnames, int nnames, int fast, void *stats_hd );
-int import_keys_stream( IOBUF inp, int fast, void *stats_hd );
+void import_keys( char **fnames, int nnames, int fast,
+                 void *stats_hd, unsigned int options );
+int import_keys_stream( IOBUF inp, int fast,
+                       void *stats_hd, unsigned int options );
 void *import_new_stats_handle (void);
 void import_release_stats_handle (void *p);
 void import_print_stats (void *hd);
@@ -168,7 +169,6 @@ int collapse_uids( KBNODE *keyblock );
 #define EXPORT_INCLUDE_LOCAL_SIGS        2
 #define EXPORT_INCLUDE_ATTRIBUTES        4
 #define EXPORT_INCLUDE_SENSITIVE_REVKEYS 8
-#define EXPORT_DEFAULT                   (1|4)
 
 int parse_export_options(char *str,unsigned int *options);
 int export_pubkeys( STRLIST users, unsigned int options );