mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-23 10:29:58 +01:00
gpg: Fallback to import with self-sigs-only on too large keyblocks.
* g10/import.c (import_one): Rename to ... (import_one_real): this. Do not print and update stats on keyring write errors. (import_one): New. Add fallback code. -- GnuPG-bug-id: 4591 Signed-off-by: Werner Koch <wk@gnupg.org> (cherry picked from commit 3a403ab04eeb45f12b34f9d9c421dac93eaf2160)
This commit is contained in:
parent
adb120e663
commit
a1f2f38dfb
122
g10/import.c
122
g10/import.c
@ -128,6 +128,7 @@ static int chk_self_sigs (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
|
|||||||
static int delete_inv_parts (ctrl_t ctrl, kbnode_t keyblock,
|
static int delete_inv_parts (ctrl_t ctrl, kbnode_t keyblock,
|
||||||
u32 *keyid, unsigned int options);
|
u32 *keyid, unsigned int options);
|
||||||
static int any_uid_left (kbnode_t keyblock);
|
static int any_uid_left (kbnode_t keyblock);
|
||||||
|
static void remove_all_non_self_sigs (kbnode_t *keyblock, u32 *keyid);
|
||||||
static int merge_blocks (ctrl_t ctrl, unsigned int options,
|
static int merge_blocks (ctrl_t ctrl, unsigned int options,
|
||||||
kbnode_t keyblock_orig,
|
kbnode_t keyblock_orig,
|
||||||
kbnode_t keyblock, u32 *keyid,
|
kbnode_t keyblock, u32 *keyid,
|
||||||
@ -1756,12 +1757,12 @@ update_key_origin (kbnode_t keyblock, u32 curtime, int origin, const char *url)
|
|||||||
* has valid parts.
|
* has valid parts.
|
||||||
*/
|
*/
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
import_one (ctrl_t ctrl,
|
import_one_real (ctrl_t ctrl,
|
||||||
kbnode_t keyblock, struct import_stats_s *stats,
|
kbnode_t keyblock, struct import_stats_s *stats,
|
||||||
unsigned char **fpr, size_t *fpr_len, unsigned int options,
|
unsigned char **fpr, size_t *fpr_len, unsigned int options,
|
||||||
int from_sk, int silent,
|
int from_sk, int silent,
|
||||||
import_screener_t screener, void *screener_arg,
|
import_screener_t screener, void *screener_arg,
|
||||||
int origin, const char *url, int *r_valid)
|
int origin, const char *url, int *r_valid)
|
||||||
{
|
{
|
||||||
gpg_error_t err = 0;
|
gpg_error_t err = 0;
|
||||||
PKT_public_key *pk;
|
PKT_public_key *pk;
|
||||||
@ -1842,6 +1843,13 @@ import_one (ctrl_t ctrl,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Remove all non-self-sigs if requested. Noe that this is a NOP if
|
||||||
|
* that option has been globally set but we may also be called
|
||||||
|
* latter with the already parsed keyblock and a locally changed
|
||||||
|
* option. This is why we need to remove them here as well. */
|
||||||
|
if ((options & IMPORT_SELF_SIGS_ONLY))
|
||||||
|
remove_all_non_self_sigs (&keyblock, keyid);
|
||||||
|
|
||||||
collapse_uids(&keyblock);
|
collapse_uids(&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
|
||||||
@ -2044,22 +2052,25 @@ import_one (ctrl_t ctrl,
|
|||||||
hd = NULL;
|
hd = NULL;
|
||||||
|
|
||||||
/* We are ready. */
|
/* We are ready. */
|
||||||
if (!opt.quiet && !silent)
|
if (!err && !opt.quiet && !silent)
|
||||||
{
|
{
|
||||||
char *p = get_user_id_byfpr_native (ctrl, fpr2);
|
char *p = get_user_id_byfpr_native (ctrl, fpr2);
|
||||||
log_info (_("key %s: public key \"%s\" imported\n"),
|
log_info (_("key %s: public key \"%s\" imported\n"),
|
||||||
keystr(keyid), p);
|
keystr(keyid), p);
|
||||||
xfree(p);
|
xfree(p);
|
||||||
}
|
}
|
||||||
if (is_status_enabled())
|
if (!err && is_status_enabled())
|
||||||
{
|
{
|
||||||
char *us = get_long_user_id_string (ctrl, keyid);
|
char *us = get_long_user_id_string (ctrl, keyid);
|
||||||
write_status_text( STATUS_IMPORTED, us );
|
write_status_text( STATUS_IMPORTED, us );
|
||||||
xfree(us);
|
xfree(us);
|
||||||
print_import_ok (pk, 1);
|
print_import_ok (pk, 1);
|
||||||
}
|
}
|
||||||
stats->imported++;
|
if (!err)
|
||||||
new_key = 1;
|
{
|
||||||
|
stats->imported++;
|
||||||
|
new_key = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else /* Key already exists - merge. */
|
else /* Key already exists - merge. */
|
||||||
{
|
{
|
||||||
@ -2129,8 +2140,10 @@ import_one (ctrl_t ctrl,
|
|||||||
keydb_release (hd);
|
keydb_release (hd);
|
||||||
hd = NULL;
|
hd = NULL;
|
||||||
|
|
||||||
/* We are ready. */
|
/* We are ready. Print and update stats if we got no error.
|
||||||
if (!opt.quiet && !silent)
|
* An error here comes from writing the keyblock and thus
|
||||||
|
* very likely means that no update happened. */
|
||||||
|
if (!err && !opt.quiet && !silent)
|
||||||
{
|
{
|
||||||
char *p = get_user_id_byfpr_native (ctrl, fpr2);
|
char *p = get_user_id_byfpr_native (ctrl, fpr2);
|
||||||
if (n_uids == 1 )
|
if (n_uids == 1 )
|
||||||
@ -2166,14 +2179,17 @@ import_one (ctrl_t ctrl,
|
|||||||
xfree(p);
|
xfree(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
stats->n_uids +=n_uids;
|
if (!err)
|
||||||
stats->n_sigs +=n_sigs;
|
{
|
||||||
stats->n_subk +=n_subk;
|
stats->n_uids +=n_uids;
|
||||||
stats->n_sigs_cleaned +=n_sigs_cleaned;
|
stats->n_sigs +=n_sigs;
|
||||||
stats->n_uids_cleaned +=n_uids_cleaned;
|
stats->n_subk +=n_subk;
|
||||||
|
stats->n_sigs_cleaned +=n_sigs_cleaned;
|
||||||
|
stats->n_uids_cleaned +=n_uids_cleaned;
|
||||||
|
|
||||||
if (is_status_enabled () && !silent)
|
if (is_status_enabled () && !silent)
|
||||||
print_import_ok (pk, ((n_uids?2:0)|(n_sigs?4:0)|(n_subk?8:0)));
|
print_import_ok (pk, ((n_uids?2:0)|(n_sigs?4:0)|(n_subk?8:0)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -2260,6 +2276,39 @@ import_one (ctrl_t ctrl,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Wrapper around import_one_real to retry the import in some cases. */
|
||||||
|
static gpg_error_t
|
||||||
|
import_one (ctrl_t ctrl,
|
||||||
|
kbnode_t keyblock, struct import_stats_s *stats,
|
||||||
|
unsigned char **fpr, size_t *fpr_len, unsigned int options,
|
||||||
|
int from_sk, int silent,
|
||||||
|
import_screener_t screener, void *screener_arg,
|
||||||
|
int origin, const char *url, int *r_valid)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
|
||||||
|
err = import_one_real (ctrl, keyblock, stats, fpr, fpr_len, options,
|
||||||
|
from_sk, silent, screener, screener_arg,
|
||||||
|
origin, url, r_valid);
|
||||||
|
if (gpg_err_code (err) == GPG_ERR_TOO_LARGE
|
||||||
|
&& gpg_err_source (err) == GPG_ERR_SOURCE_KEYBOX)
|
||||||
|
{
|
||||||
|
/* We hit the maximum image length. Ask the wrapper to do
|
||||||
|
* everything again but this time with some extra options. */
|
||||||
|
u32 keyid[2];
|
||||||
|
|
||||||
|
keyid_from_pk (keyblock->pkt->pkt.public_key, keyid);
|
||||||
|
log_info ("key %s: keyblock too large, retrying with self-sigs-only\n",
|
||||||
|
keystr (keyid));
|
||||||
|
options |= IMPORT_SELF_SIGS_ONLY | IMPORT_CLEAN;
|
||||||
|
err = import_one_real (ctrl, keyblock, stats, fpr, fpr_len, options,
|
||||||
|
from_sk, silent, screener, screener_arg,
|
||||||
|
origin, url, r_valid);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Transfer all the secret keys in SEC_KEYBLOCK to the gpg-agent. The
|
/* Transfer all the secret keys in SEC_KEYBLOCK to the gpg-agent. The
|
||||||
* function prints diagnostics and returns an error code. If BATCH is
|
* function prints diagnostics and returns an error code. If BATCH is
|
||||||
* true the secret keys are stored by gpg-agent in the transfer format
|
* true the secret keys are stored by gpg-agent in the transfer format
|
||||||
@ -2937,7 +2986,7 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
|
|||||||
/* The secret keyblock may not have nodes which are deleted in
|
/* The secret keyblock may not have nodes which are deleted in
|
||||||
* the public keyblock. Otherwise we would import just the
|
* the public keyblock. Otherwise we would import just the
|
||||||
* secret key without having the public key. That would be
|
* secret key without having the public key. That would be
|
||||||
* surprising and clutters out private-keys-v1.d. */
|
* surprising and clutters our private-keys-v1.d. */
|
||||||
err = resync_sec_with_pub_keyblock (&keyblock, pub_keyblock, &attic);
|
err = resync_sec_with_pub_keyblock (&keyblock, pub_keyblock, &attic);
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
@ -3750,8 +3799,39 @@ any_uid_left (kbnode_t keyblock)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Delete all non-self-sigs from KEYBLOCK.
|
||||||
|
* Returns: True if the keyblock has changed. */
|
||||||
|
static void
|
||||||
|
remove_all_non_self_sigs (kbnode_t *keyblock, u32 *keyid)
|
||||||
|
{
|
||||||
|
kbnode_t node;
|
||||||
|
unsigned int dropped = 0;
|
||||||
|
|
||||||
/****************
|
for (node = *keyblock; node; node = node->next)
|
||||||
|
{
|
||||||
|
if (is_deleted_kbnode (node))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (node->pkt->pkttype != PKT_SIGNATURE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (node->pkt->pkt.signature->keyid[0] == keyid[0]
|
||||||
|
&& node->pkt->pkt.signature->keyid[1] == keyid[1])
|
||||||
|
continue;
|
||||||
|
delete_kbnode (node);
|
||||||
|
dropped++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dropped)
|
||||||
|
commit_kbnode (keyblock);
|
||||||
|
|
||||||
|
if (dropped && opt.verbose)
|
||||||
|
log_info ("key %s: number of dropped non-self-signatures: %u\n",
|
||||||
|
keystr (keyid), dropped);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
* It may happen that the imported keyblock has duplicated user IDs.
|
* It may happen that the imported keyblock has duplicated user IDs.
|
||||||
* We check this here and collapse those user IDs together with their
|
* We check this here and collapse those user IDs together with their
|
||||||
* sigs into one.
|
* sigs into one.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user