mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-03 12:11:33 +01:00
gpg: Collapse duplicate subkeys.
* g10/options.h (IMPORT_COLLAPSE_UIDS): New. (IMPORT_COLLAPSE_SUBKEYS): New. * g10/gpg.c (main): Make them the default. * g10/import.c (parse_import_options): New import options "no-collapse-uids" and "no-collapse_subkeys". (collapse_subkeys): New. (import_one_real): Collapse subkeys and allow disabling the collapsing using the new options. (read_key_from_file_or_buffer): Always collapse subkeys. * g10/keyedit.c (fix_keyblock): Call collapse_subkeys. -- GnuPG-bug-id: 4421 Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
96e15051ba
commit
633c1fea5f
@ -2391,11 +2391,15 @@ main (int argc, char **argv)
|
||||
opt.max_cert_depth = 5;
|
||||
opt.escape_from = 1;
|
||||
opt.flags.require_cross_cert = 1;
|
||||
opt.import_options = IMPORT_REPAIR_KEYS;
|
||||
opt.import_options = (IMPORT_REPAIR_KEYS
|
||||
| IMPORT_COLLAPSE_UIDS
|
||||
| IMPORT_COLLAPSE_SUBKEYS);
|
||||
opt.export_options = EXPORT_ATTRIBUTES;
|
||||
opt.keyserver_options.import_options = (IMPORT_REPAIR_KEYS
|
||||
| IMPORT_REPAIR_PKS_SUBKEY_BUG
|
||||
| IMPORT_SELF_SIGS_ONLY
|
||||
| IMPORT_COLLAPSE_UIDS
|
||||
| IMPORT_COLLAPSE_SUBKEYS
|
||||
| IMPORT_CLEAN);
|
||||
opt.keyserver_options.export_options = EXPORT_ATTRIBUTES;
|
||||
opt.keyserver_options.options = KEYSERVER_HONOR_PKA_RECORD;
|
||||
|
124
g10/import.c
124
g10/import.c
@ -210,6 +210,11 @@ parse_import_options(char *str,unsigned int *options,int noisy)
|
||||
{"show-only", (IMPORT_SHOW | IMPORT_DRY_RUN), NULL,
|
||||
NULL},
|
||||
|
||||
/* Hidden options which are enabled by default and are provided
|
||||
* in case of problems with the respective implementation. */
|
||||
{"collapse-uids", IMPORT_COLLAPSE_UIDS, NULL, NULL},
|
||||
{"collapse-subkeys", IMPORT_COLLAPSE_SUBKEYS, NULL, NULL},
|
||||
|
||||
/* Aliases for backward compatibility */
|
||||
{"allow-local-sigs",IMPORT_LOCAL_SIGS,NULL,NULL},
|
||||
{"repair-hkp-subkey-bug",IMPORT_REPAIR_PKS_SUBKEY_BUG,NULL,NULL},
|
||||
@ -403,7 +408,10 @@ read_key_from_file_or_buffer (ctrl_t ctrl, const char *fname,
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* We do the collapsing unconditionally although it is expected that
|
||||
* clean keys are provided here. */
|
||||
collapse_uids (&keyblock);
|
||||
collapse_subkeys (&keyblock);
|
||||
|
||||
clear_kbnode_flags (keyblock);
|
||||
if (chk_self_sigs (ctrl, keyblock, keyid, &non_self))
|
||||
@ -1947,9 +1955,12 @@ import_one_real (ctrl_t ctrl,
|
||||
/* Remove or collapse the user ids. */
|
||||
if ((options & IMPORT_DROP_UIDS))
|
||||
remove_all_uids (&keyblock);
|
||||
else
|
||||
else if ((options & IMPORT_COLLAPSE_UIDS))
|
||||
collapse_uids (&keyblock);
|
||||
|
||||
if ((options & IMPORT_COLLAPSE_SUBKEYS))
|
||||
collapse_subkeys (&keyblock);
|
||||
|
||||
/* Clean the key that we're about to import, to cut down on things
|
||||
that we have to clean later. This has no practical impact on the
|
||||
end result, but does result in less logging which might confuse
|
||||
@ -3010,7 +3021,7 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
|
||||
_("rejected by import screener"));
|
||||
release_kbnode (keyblock);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (opt.verbose && !for_migration)
|
||||
{
|
||||
@ -4100,6 +4111,115 @@ collapse_uids (kbnode_t *keyblock)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* It may happen that the imported keyblock has duplicated subkeys.
|
||||
* We check this here and collapse those subkeys along with their
|
||||
* binding self-signatures.
|
||||
* Returns: True if the keyblock has changed.
|
||||
*/
|
||||
int
|
||||
collapse_subkeys (kbnode_t *keyblock)
|
||||
{
|
||||
kbnode_t kb1, kb2, sig1, sig2, last;
|
||||
int any = 0;
|
||||
|
||||
log_debug ("enter collapse_subkeys\n");
|
||||
for (kb1 = *keyblock; kb1; kb1 = kb1->next)
|
||||
{
|
||||
if (is_deleted_kbnode (kb1))
|
||||
continue;
|
||||
|
||||
if (kb1->pkt->pkttype != PKT_PUBLIC_SUBKEY
|
||||
&& kb1->pkt->pkttype != PKT_SECRET_SUBKEY)
|
||||
continue;
|
||||
|
||||
/* We assume just a few duplicates and use a straightforward
|
||||
* algorithm. */
|
||||
for (kb2 = kb1->next; kb2; kb2 = kb2->next)
|
||||
{
|
||||
if (is_deleted_kbnode (kb2))
|
||||
continue;
|
||||
|
||||
if (kb2->pkt->pkttype != PKT_PUBLIC_SUBKEY
|
||||
&& kb2->pkt->pkttype != PKT_SECRET_SUBKEY)
|
||||
continue;
|
||||
|
||||
if (cmp_public_keys (kb1->pkt->pkt.public_key,
|
||||
kb2->pkt->pkt.public_key))
|
||||
continue;
|
||||
|
||||
/* We have a duplicated subkey. */
|
||||
any = 1;
|
||||
|
||||
/* Take subkey-2's signatures, and attach them to subkey-1. */
|
||||
for (last = kb2; last->next; last = last->next)
|
||||
{
|
||||
if (is_deleted_kbnode (last))
|
||||
continue;
|
||||
|
||||
if (last->next->pkt->pkttype != PKT_SIGNATURE)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Snip out subkye-2 */
|
||||
find_prev_kbnode (*keyblock, kb2, 0)->next = last->next;
|
||||
|
||||
/* Put subkey-2 in place as part of subkey-1 */
|
||||
last->next = kb1->next;
|
||||
kb1->next = kb2;
|
||||
delete_kbnode (kb2);
|
||||
|
||||
/* Now dedupe kb1 */
|
||||
for (sig1 = kb1->next; sig1; sig1 = sig1->next)
|
||||
{
|
||||
if (is_deleted_kbnode (sig1))
|
||||
continue;
|
||||
|
||||
if (sig1->pkt->pkttype != PKT_SIGNATURE)
|
||||
break;
|
||||
|
||||
for (sig2 = sig1->next, last = sig1;
|
||||
sig2;
|
||||
last = sig2, sig2 = sig2->next)
|
||||
{
|
||||
if (is_deleted_kbnode (sig2))
|
||||
continue;
|
||||
|
||||
if (sig2->pkt->pkttype != PKT_SIGNATURE)
|
||||
break;
|
||||
|
||||
if (!cmp_signatures (sig1->pkt->pkt.signature,
|
||||
sig2->pkt->pkt.signature))
|
||||
{
|
||||
/* We have a match, so delete the second
|
||||
signature */
|
||||
delete_kbnode (sig2);
|
||||
sig2 = last;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
commit_kbnode (keyblock);
|
||||
|
||||
log_debug ("leave collapse_subkeys (any=%d)\n", any);
|
||||
if (any && !opt.quiet)
|
||||
{
|
||||
const char *key="???";
|
||||
|
||||
if ((kb1 = find_kbnode (*keyblock, PKT_PUBLIC_KEY)) )
|
||||
key = keystr_from_pk (kb1->pkt->pkt.public_key);
|
||||
else if ((kb1 = find_kbnode (*keyblock, PKT_SECRET_KEY)) )
|
||||
key = keystr_from_pk (kb1->pkt->pkt.public_key);
|
||||
|
||||
log_info (_("key %s: duplicated subkeys detected - merged\n"), key);
|
||||
}
|
||||
|
||||
return any;
|
||||
}
|
||||
|
||||
|
||||
/* Check for a 0x20 revocation from a revocation key that is not
|
||||
present. This may be called without the benefit of merge_xxxx so
|
||||
you can't rely on pk->revkey and friends. */
|
||||
|
@ -1174,6 +1174,8 @@ fix_keyblock (ctrl_t ctrl, kbnode_t *keyblockp)
|
||||
|
||||
if (collapse_uids (keyblockp))
|
||||
changed++;
|
||||
if (collapse_subkeys (keyblockp))
|
||||
changed++;
|
||||
if (key_check_all_keysigs (ctrl, 1, *keyblockp, 0, 1))
|
||||
changed++;
|
||||
reorder_keyblock (*keyblockp);
|
||||
|
@ -394,7 +394,8 @@ gpg_error_t transfer_secret_keys (ctrl_t ctrl, struct import_stats_s *stats,
|
||||
kbnode_t sec_keyblock, int batch, int force,
|
||||
int only_marked);
|
||||
|
||||
int collapse_uids( KBNODE *keyblock );
|
||||
int collapse_uids (kbnode_t *keyblock);
|
||||
int collapse_subkeys (kbnode_t *keyblock);
|
||||
|
||||
int get_revocation_reason (PKT_signature *sig, char **r_reason,
|
||||
char **r_comment, size_t *r_commentlen);
|
||||
|
@ -369,6 +369,8 @@ EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode;
|
||||
#define IMPORT_DRY_RUN (1<<12)
|
||||
#define IMPORT_DROP_UIDS (1<<13)
|
||||
#define IMPORT_SELF_SIGS_ONLY (1<<14)
|
||||
#define IMPORT_COLLAPSE_UIDS (1<<15)
|
||||
#define IMPORT_COLLAPSE_SUBKEYS (1<<16)
|
||||
|
||||
#define EXPORT_LOCAL_SIGS (1<<0)
|
||||
#define EXPORT_ATTRIBUTES (1<<1)
|
||||
|
Loading…
x
Reference in New Issue
Block a user