mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-03 12:11:33 +01:00
g10: Don't consider cross-signed keys to be in conflict.
* g10/tofu.c (cross_sigs): New function. (ask_about_binding): If apparently conflicting keys are cross signed, then don't mark them as conflicting. -- Signed-off-by: Neal H. Walfield <neal@g10code.com> If two keys are cross signed, then the same person (probably) controlled them both. In this case, don't raise a TOFU conflict. This usually occurs when someone transitions to a new key. When that person rotates to a third key, she will typically only cross sign it with the second key. As such, we check this transitively to avoid declaring a conflict between the 1st and 3rd key.
This commit is contained in:
parent
38d369de13
commit
b410a3cb76
162
g10/tofu.c
162
g10/tofu.c
@ -1204,6 +1204,80 @@ format_conflict_msg_part1 (int policy, const char *conflict,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return 1 if A signed B and B signed A. */
|
||||||
|
int
|
||||||
|
cross_sigs (kbnode_t a, kbnode_t b)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
PKT_public_key *a_pk = a->pkt->pkt.public_key;
|
||||||
|
PKT_public_key *b_pk = b->pkt->pkt.public_key;
|
||||||
|
|
||||||
|
char a_keyid[33];
|
||||||
|
char b_keyid[33];
|
||||||
|
|
||||||
|
if (DBG_TRUST)
|
||||||
|
{
|
||||||
|
format_keyid (pk_main_keyid (a_pk),
|
||||||
|
KF_DEFAULT, a_keyid, sizeof (a_keyid));
|
||||||
|
format_keyid (pk_main_keyid (b_pk),
|
||||||
|
KF_DEFAULT, b_keyid, sizeof (b_keyid));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i ++)
|
||||||
|
{
|
||||||
|
/* See if SIGNER signed SIGNEE. */
|
||||||
|
|
||||||
|
kbnode_t signer = i == 0 ? a : b;
|
||||||
|
kbnode_t signee = i == 0 ? b : a;
|
||||||
|
|
||||||
|
PKT_public_key *signer_pk = signer->pkt->pkt.public_key;
|
||||||
|
u32 *signer_kid = pk_main_keyid (signer_pk);
|
||||||
|
kbnode_t n;
|
||||||
|
|
||||||
|
/* Iterate over SIGNEE's keyblock and see if there is a valid
|
||||||
|
signature from SIGNER. */
|
||||||
|
for (n = signee; n; n = n->next)
|
||||||
|
{
|
||||||
|
PKT_signature *sig;
|
||||||
|
|
||||||
|
if (n->pkt->pkttype != PKT_SIGNATURE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
sig = n->pkt->pkt.signature;
|
||||||
|
|
||||||
|
if (! (sig->sig_class == 0x10
|
||||||
|
|| sig->sig_class == 0x11
|
||||||
|
|| sig->sig_class == 0x12
|
||||||
|
|| sig->sig_class == 0x13))
|
||||||
|
/* Not a signature over a user id. */
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* SIG is on SIGNEE's keyblock. If SIG was generated by the
|
||||||
|
signer, then it's a match. */
|
||||||
|
if (keyid_cmp (sig->keyid, signer_kid) == 0)
|
||||||
|
/* Match! */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (! n)
|
||||||
|
/* We didn't find a signature from signer over signee. */
|
||||||
|
{
|
||||||
|
if (DBG_TRUST)
|
||||||
|
log_info ("No cross sig between %s and %s\n",
|
||||||
|
a_keyid, b_keyid);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A signed B and B signed A. */
|
||||||
|
if (DBG_TRUST)
|
||||||
|
log_info ("Cross sig between %s and %s\n",
|
||||||
|
a_keyid, b_keyid);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Ask the user about the binding. There are three ways we could end
|
/* Ask the user about the binding. There are three ways we could end
|
||||||
* up here:
|
* up here:
|
||||||
*
|
*
|
||||||
@ -1237,7 +1311,7 @@ ask_about_binding (ctrl_t ctrl,
|
|||||||
strlist_t other_user_ids = NULL;
|
strlist_t other_user_ids = NULL;
|
||||||
struct signature_stats *stats = NULL;
|
struct signature_stats *stats = NULL;
|
||||||
struct signature_stats *stats_iter = NULL;
|
struct signature_stats *stats_iter = NULL;
|
||||||
char *prompt;
|
char *prompt = NULL;
|
||||||
char *choices;
|
char *choices;
|
||||||
|
|
||||||
dbs = ctrl->tofu.dbs;
|
dbs = ctrl->tofu.dbs;
|
||||||
@ -1361,9 +1435,17 @@ ask_about_binding (ctrl_t ctrl,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
int stats_count = 0;
|
||||||
|
kbnode_t *kb_all;
|
||||||
KEYDB_HANDLE hd;
|
KEYDB_HANDLE hd;
|
||||||
|
int i;
|
||||||
char *key = NULL;
|
char *key = NULL;
|
||||||
|
|
||||||
|
/* Get the keyblock for each key. */
|
||||||
|
for (stats_iter = stats; stats_iter; stats_iter = stats_iter->next)
|
||||||
|
stats_count ++;
|
||||||
|
kb_all = xcalloc (sizeof (kb_all[0]), stats_count);
|
||||||
|
|
||||||
if (! stats || strcmp (stats->fingerprint, fingerprint))
|
if (! stats || strcmp (stats->fingerprint, fingerprint))
|
||||||
{
|
{
|
||||||
/* If we have already added this key to the DB, then it will
|
/* If we have already added this key to the DB, then it will
|
||||||
@ -1375,7 +1457,9 @@ ask_about_binding (ctrl_t ctrl,
|
|||||||
|
|
||||||
/* Figure out which user ids are revoked or expired. */
|
/* Figure out which user ids are revoked or expired. */
|
||||||
hd = keydb_new ();
|
hd = keydb_new ();
|
||||||
for (stats_iter = stats; stats_iter; stats_iter = stats_iter->next)
|
for (stats_iter = stats, i = 0;
|
||||||
|
stats_iter;
|
||||||
|
stats_iter = stats_iter->next, i ++)
|
||||||
{
|
{
|
||||||
KEYDB_SEARCH_DESC desc;
|
KEYDB_SEARCH_DESC desc;
|
||||||
kbnode_t kb;
|
kbnode_t kb;
|
||||||
@ -1420,6 +1504,9 @@ ask_about_binding (ctrl_t ctrl,
|
|||||||
merge_keys_and_selfsig (kb);
|
merge_keys_and_selfsig (kb);
|
||||||
|
|
||||||
log_assert (kb->pkt->pkttype == PKT_PUBLIC_KEY);
|
log_assert (kb->pkt->pkttype == PKT_PUBLIC_KEY);
|
||||||
|
|
||||||
|
kb_all[i] = kb;
|
||||||
|
|
||||||
pk = kb->pkt->pkt.public_key;
|
pk = kb->pkt->pkt.public_key;
|
||||||
|
|
||||||
if (pk->has_expired)
|
if (pk->has_expired)
|
||||||
@ -1451,7 +1538,6 @@ ask_about_binding (ctrl_t ctrl,
|
|||||||
|
|
||||||
xfree (email2);
|
xfree (email2);
|
||||||
}
|
}
|
||||||
release_kbnode (kb);
|
|
||||||
|
|
||||||
if (! found_user_id)
|
if (! found_user_id)
|
||||||
log_info (_("TOFU db may be corrupted: user id (%s)"
|
log_info (_("TOFU db may be corrupted: user id (%s)"
|
||||||
@ -1460,7 +1546,74 @@ ask_about_binding (ctrl_t ctrl,
|
|||||||
}
|
}
|
||||||
keydb_release (hd);
|
keydb_release (hd);
|
||||||
|
|
||||||
es_fprintf (fp, _("Statistics for keys with the email address \"%s\":\n"),
|
{
|
||||||
|
int j;
|
||||||
|
struct signature_stats **stats_prevp;
|
||||||
|
struct signature_stats *stats_iter_next;
|
||||||
|
int die[stats_count];
|
||||||
|
|
||||||
|
memset (die, 0, sizeof (die));
|
||||||
|
|
||||||
|
for (i = 0; i < stats_count; i ++)
|
||||||
|
{
|
||||||
|
/* i or a key that has cross sigs with i (possible
|
||||||
|
indirectly)? */
|
||||||
|
if (! (i == 0 || die[i]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (j = i + 1; j < stats_count; j ++)
|
||||||
|
if (cross_sigs (kb_all[i], kb_all[j]))
|
||||||
|
die[j] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free the dead stat structures. */
|
||||||
|
for (stats_iter = stats, stats_prevp = &stats, i = 0;
|
||||||
|
stats_iter;
|
||||||
|
stats_iter = stats_iter_next, i ++)
|
||||||
|
{
|
||||||
|
stats_iter_next = stats_iter->next;
|
||||||
|
|
||||||
|
release_kbnode (kb_all[i]);
|
||||||
|
|
||||||
|
if (die[i])
|
||||||
|
{
|
||||||
|
*stats_prevp = stats_iter_next;
|
||||||
|
stats_iter->next = NULL;
|
||||||
|
signature_stats_free (stats_iter);
|
||||||
|
|
||||||
|
bindings_with_this_email_count --;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stats_prevp = &stats_iter->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log_assert (stats);
|
||||||
|
log_assert (bindings_with_this_email_count >= 1);
|
||||||
|
|
||||||
|
if ((*policy == TOFU_POLICY_NONE && bindings_with_this_email_count == 1)
|
||||||
|
|| (*policy == TOFU_POLICY_ASK && conflict))
|
||||||
|
if (bindings_with_this_email_count == 1)
|
||||||
|
{
|
||||||
|
/* All "conflicts" were not really conflicts. */
|
||||||
|
log_assert (! stats->next);
|
||||||
|
|
||||||
|
if (DBG_TRUST)
|
||||||
|
log_debug ("%s: all apparent TOFU conflicts are legitimate "
|
||||||
|
"(cross sigs), setting policy to auto.\n",
|
||||||
|
stats_iter->fingerprint);
|
||||||
|
|
||||||
|
*policy = TOFU_POLICY_AUTO;
|
||||||
|
record_binding (dbs, fingerprint, email, user_id, *policy, 0);
|
||||||
|
*trust_level = tofu_policy_to_trust_level (*policy);
|
||||||
|
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
es_fprintf (fp, _("Statistics for potentially conflicting keys"
|
||||||
|
" with the email address \"%s\":\n"),
|
||||||
email);
|
email);
|
||||||
for (stats_iter = stats; stats_iter; stats_iter = stats_iter->next)
|
for (stats_iter = stats; stats_iter; stats_iter = stats_iter->next)
|
||||||
{
|
{
|
||||||
@ -1644,6 +1797,7 @@ ask_about_binding (ctrl_t ctrl,
|
|||||||
}
|
}
|
||||||
xfree (response);
|
xfree (response);
|
||||||
}
|
}
|
||||||
|
out:
|
||||||
tofu_resume_batch_transaction (ctrl);
|
tofu_resume_batch_transaction (ctrl);
|
||||||
|
|
||||||
xfree (prompt);
|
xfree (prompt);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user