aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Shaw <[email protected]>2002-07-24 21:17:19 +0000
committerDavid Shaw <[email protected]>2002-07-24 21:17:19 +0000
commit553ac3f08c996f38ddb652aa58cd5b583c347d76 (patch)
tree3db239e8bcffdf2b659bfa08bd86fac4c8ffe77c
parent* options.h, exec.h, exec.c (set_exec_path, exec_write), g10.c (main), (diff)
downloadgnupg-553ac3f08c996f38ddb652aa58cd5b583c347d76.tar.gz
gnupg-553ac3f08c996f38ddb652aa58cd5b583c347d76.zip
* 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.
-rw-r--r--g10/ChangeLog10
-rw-r--r--g10/g10.c13
-rw-r--r--g10/hkp.c3
-rw-r--r--g10/import.c101
-rw-r--r--g10/keyserver.c3
-rw-r--r--g10/main.h12
6 files changed, 116 insertions, 26 deletions
diff --git a/g10/ChangeLog b/g10/ChangeLog
index 02de71b4e..8478edce6 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -1,5 +1,15 @@
2002-07-24 David Shaw <[email protected]>
+ * 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
diff --git a/g10/g10.c b/g10/g10.c
index 7a1b624f3..fc50781a2 100644
--- 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:
diff --git a/g10/hkp.c b/g10/hkp.c
index 09fa5a12a..234a57835 100644
--- 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 );
}
diff --git a/g10/import.c b/g10/import.c
index 415e26ef6..4be313f74 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -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
diff --git a/g10/keyserver.c b/g10/keyserver.c
index c64ad4bc8..97745f0d6 100644
--- a/g10/keyserver.c
+++ b/g10/keyserver.c
@@ -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);
diff --git a/g10/main.h b/g10/main.h
index 05da9c80c..9edccaf21 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -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 );