aboutsummaryrefslogtreecommitdiffstats
path: root/g10/import.c
diff options
context:
space:
mode:
Diffstat (limited to 'g10/import.c')
-rw-r--r--g10/import.c91
1 files changed, 91 insertions, 0 deletions
diff --git a/g10/import.c b/g10/import.c
index 5e5a28c02..ccc665145 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -395,6 +395,95 @@ remove_bad_stuff (KBNODE keyblock)
}
}
+/* 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
+ revocation targets, this may need to be revised. */
+
+static int
+clean_subkeys(KBNODE keyblock,u32 *keyid)
+{
+ int removed=0;
+ KBNODE node,sknode=keyblock;
+
+ while((sknode=find_kbnode(sknode,PKT_PUBLIC_SUBKEY)))
+ {
+ KBNODE bsnode=NULL,rsnode=NULL;
+ u32 bsdate=0,rsdate=0;
+
+ sknode=sknode->next;
+
+ for(node=sknode;node;node=node->next)
+ {
+ if(node->pkt->pkttype==PKT_SIGNATURE)
+ {
+ PKT_signature *sig=node->pkt->pkt.signature;
+
+ /* We're only interested in valid sigs */
+ if(check_key_signature(keyblock,node,NULL))
+ continue;
+
+ if(IS_SUBKEY_SIG(sig) && bsdate<=sig->timestamp)
+ {
+ bsnode=node;
+ bsdate=sig->timestamp;
+ }
+ else if(IS_SUBKEY_REV(sig) && rsdate<=sig->timestamp)
+ {
+ rsnode=node;
+ rsdate=sig->timestamp;
+ }
+ /* If it's not a subkey sig or rev, then it shouldn't be
+ here so ignore it. */
+ }
+ else
+ break;
+ }
+
+ /* We now know the most recent binding sig and revocation sig
+ (if any). If the binding sig is more recent than the
+ revocation sig, strip everything but the binding sig. If the
+ revocation sig is more recent than the binding sig, strip
+ everything but the binding sig and the revocation sig. */
+
+ if(bsdate>=rsdate)
+ {
+ rsnode=NULL;
+ rsdate=0;
+ }
+
+ for(node=sknode;node;node=node->next)
+ {
+ if(node->pkt->pkttype==PKT_SIGNATURE)
+ {
+ PKT_signature *sig=node->pkt->pkt.signature;
+
+ if(IS_SUBKEY_SIG(sig) && node!=bsnode)
+ {
+ delete_kbnode(node);
+ removed++;
+ }
+ else if(IS_SUBKEY_REV(sig) && node!=rsnode)
+ {
+ delete_kbnode(node);
+ removed++;
+ }
+ }
+ else
+ break;
+ }
+ }
+
+ if(removed)
+ {
+ log_info(_("key %08lX: removed multiple subkey binding\n"),
+ (ulong)keyid[1]);
+ commit_kbnode(&keyblock);
+ }
+
+ return removed;
+}
+
/****************
* Try to import one keyblock. Return an error only in serious cases, but
@@ -492,6 +581,7 @@ import_one( const char *fname, KBNODE keyblock, int fast,
}
if( opt.verbose > 1 )
log_info (_("writing to `%s'\n"), keydb_get_resource_name (hd) );
+ clean_subkeys(keyblock,keyid);
rc = keydb_insert_keyblock (hd, keyblock );
if (rc)
log_error (_("error writing keyring `%s': %s\n"),
@@ -568,6 +658,7 @@ import_one( const char *fname, KBNODE keyblock, int fast,
if( n_uids || n_sigs || n_subk ) {
mod_key = 1;
/* keyblock_orig has been updated; write */
+ n_sigs-=clean_subkeys(keyblock_orig,keyid);
rc = keydb_update_keyblock (hd, keyblock_orig);
if (rc)
log_error (_("error writing keyring `%s': %s\n"),