mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-20 14:37:08 +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.max_cert_depth = 5;
|
||||||
opt.escape_from = 1;
|
opt.escape_from = 1;
|
||||||
opt.flags.require_cross_cert = 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.export_options = EXPORT_ATTRIBUTES;
|
||||||
opt.keyserver_options.import_options = (IMPORT_REPAIR_KEYS
|
opt.keyserver_options.import_options = (IMPORT_REPAIR_KEYS
|
||||||
| IMPORT_REPAIR_PKS_SUBKEY_BUG
|
| IMPORT_REPAIR_PKS_SUBKEY_BUG
|
||||||
| IMPORT_SELF_SIGS_ONLY
|
| IMPORT_SELF_SIGS_ONLY
|
||||||
|
| IMPORT_COLLAPSE_UIDS
|
||||||
|
| IMPORT_COLLAPSE_SUBKEYS
|
||||||
| IMPORT_CLEAN);
|
| IMPORT_CLEAN);
|
||||||
opt.keyserver_options.export_options = EXPORT_ATTRIBUTES;
|
opt.keyserver_options.export_options = EXPORT_ATTRIBUTES;
|
||||||
opt.keyserver_options.options = KEYSERVER_HONOR_PKA_RECORD;
|
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,
|
{"show-only", (IMPORT_SHOW | IMPORT_DRY_RUN), NULL,
|
||||||
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 */
|
/* Aliases for backward compatibility */
|
||||||
{"allow-local-sigs",IMPORT_LOCAL_SIGS,NULL,NULL},
|
{"allow-local-sigs",IMPORT_LOCAL_SIGS,NULL,NULL},
|
||||||
{"repair-hkp-subkey-bug",IMPORT_REPAIR_PKS_SUBKEY_BUG,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;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We do the collapsing unconditionally although it is expected that
|
||||||
|
* clean keys are provided here. */
|
||||||
collapse_uids (&keyblock);
|
collapse_uids (&keyblock);
|
||||||
|
collapse_subkeys (&keyblock);
|
||||||
|
|
||||||
clear_kbnode_flags (keyblock);
|
clear_kbnode_flags (keyblock);
|
||||||
if (chk_self_sigs (ctrl, keyblock, keyid, &non_self))
|
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. */
|
/* Remove or collapse the user ids. */
|
||||||
if ((options & IMPORT_DROP_UIDS))
|
if ((options & IMPORT_DROP_UIDS))
|
||||||
remove_all_uids (&keyblock);
|
remove_all_uids (&keyblock);
|
||||||
else
|
else if ((options & IMPORT_COLLAPSE_UIDS))
|
||||||
collapse_uids (&keyblock);
|
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
|
/* 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
|
that we have to clean later. This has no practical impact on the
|
||||||
end result, but does result in less logging which might confuse
|
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"));
|
_("rejected by import screener"));
|
||||||
release_kbnode (keyblock);
|
release_kbnode (keyblock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt.verbose && !for_migration)
|
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
|
/* Check for a 0x20 revocation from a revocation key that is not
|
||||||
present. This may be called without the benefit of merge_xxxx so
|
present. This may be called without the benefit of merge_xxxx so
|
||||||
you can't rely on pk->revkey and friends. */
|
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))
|
if (collapse_uids (keyblockp))
|
||||||
changed++;
|
changed++;
|
||||||
|
if (collapse_subkeys (keyblockp))
|
||||||
|
changed++;
|
||||||
if (key_check_all_keysigs (ctrl, 1, *keyblockp, 0, 1))
|
if (key_check_all_keysigs (ctrl, 1, *keyblockp, 0, 1))
|
||||||
changed++;
|
changed++;
|
||||||
reorder_keyblock (*keyblockp);
|
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,
|
kbnode_t sec_keyblock, int batch, int force,
|
||||||
int only_marked);
|
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,
|
int get_revocation_reason (PKT_signature *sig, char **r_reason,
|
||||||
char **r_comment, size_t *r_commentlen);
|
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_DRY_RUN (1<<12)
|
||||||
#define IMPORT_DROP_UIDS (1<<13)
|
#define IMPORT_DROP_UIDS (1<<13)
|
||||||
#define IMPORT_SELF_SIGS_ONLY (1<<14)
|
#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_LOCAL_SIGS (1<<0)
|
||||||
#define EXPORT_ATTRIBUTES (1<<1)
|
#define EXPORT_ATTRIBUTES (1<<1)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user