[Pkg-gnupg-commit] [gnupg2] 20/118: g10: Change tofu_register & tofu_get_validity to process multiple uids.
Daniel Kahn Gillmor
dkg at fifthhorseman.net
Thu Sep 15 18:25:00 UTC 2016
This is an automated email from the git hooks/post-receive script.
dkg pushed a commit to branch encoding-and-speling
in repository gnupg2.
commit 6052c147091935fc0321ba24f4a44146df70ef01
Author: Neal H. Walfield <neal at g10code.com>
Date: Mon Aug 29 16:16:44 2016 +0200
g10: Change tofu_register & tofu_get_validity to process multiple uids.
* g10/tofu.c (tofu_register): Take a list of user ids, not a single
user id. Only register the bindings, don't compute the trust. Thus,
change return type to an int and remove the may_ask parameter. Update
callers.
(tofu_get_validity): Take a list of user ids, not a single user id.
Update callers. Observe signatures made by expired user ids, but
don't include them in the trust calculation.
--
Signed-off-by: Neal H. Walfield <neal at g10code.com>
---
g10/tofu.c | 304 ++++++++++++++++++++++++++++++++--------------------------
g10/tofu.h | 38 ++++----
g10/trustdb.c | 93 +++++++++---------
3 files changed, 238 insertions(+), 197 deletions(-)
diff --git a/g10/tofu.c b/g10/tofu.c
index 809dac9..da09cd5 100644
--- a/g10/tofu.c
+++ b/g10/tofu.c
@@ -2164,8 +2164,9 @@ email_from_user_id (const char *user_id)
return email;
}
-/* Register the signature with the binding <fingerprint, USER_ID>.
- The fingerprint is taken from the primary key packet PK.
+/* Register the signature with the bindings <fingerprint, USER_ID>,
+ for each USER_ID in USER_ID_LIST. The fingerprint is taken from
+ the primary key packet PK.
SIG_DIGEST_BIN is the binary representation of the message's
digest. SIG_DIGEST_BIN_LEN is its length.
@@ -2181,159 +2182,152 @@ email_from_user_id (const char *user_id)
This is necessary if there is a conflict or the binding's policy is
TOFU_POLICY_ASK.
- This function returns the binding's trust level on return. If an
- error occurs, this function returns TRUST_UNKNOWN. */
-int
-tofu_register (ctrl_t ctrl, PKT_public_key *pk, const char *user_id,
+ This function returns 0 on success and an error code if an error
+ occured. */
+gpg_error_t
+tofu_register (ctrl_t ctrl, PKT_public_key *pk, strlist_t user_id_list,
const byte *sig_digest_bin, int sig_digest_bin_len,
- time_t sig_time, const char *origin, int may_ask)
+ time_t sig_time, const char *origin)
{
+ gpg_error_t rc;
tofu_dbs_t dbs;
char *fingerprint = NULL;
+ strlist_t user_id;
char *email = NULL;
char *err = NULL;
- int rc;
- int trust_level = TRUST_UNKNOWN;
char *sig_digest;
unsigned long c;
- int already_verified = 0;
-
- sig_digest = make_radix64_string (sig_digest_bin, sig_digest_bin_len);
dbs = opendbs (ctrl);
if (! dbs)
{
+ rc = gpg_error (GPG_ERR_GENERAL);
log_error (_("error opening TOFU database: %s\n"),
- gpg_strerror (GPG_ERR_GENERAL));
- goto die;
+ gpg_strerror (rc));
+ return rc;
}
- fingerprint = hexfingerprint (pk, NULL, 0);
-
- if (! *user_id)
- {
- log_debug ("TOFU: user id is empty. Can't continue.\n");
- goto die;
- }
+ /* We do a query and then an insert. Make sure they are atomic
+ by wrapping them in a transaction. */
+ rc = begin_transaction (ctrl, 0);
+ if (rc)
+ return rc;
- email = email_from_user_id (user_id);
+ sig_digest = make_radix64_string (sig_digest_bin, sig_digest_bin_len);
+ fingerprint = hexfingerprint (pk, NULL, 0);
if (! origin)
/* The default origin is simply "unknown". */
origin = "unknown";
- /* It's necessary to get the trust so that we are certain that the
- binding has been registered. */
- trust_level = get_trust (dbs, pk, fingerprint, email, user_id, may_ask);
- if (trust_level == _tofu_GET_TRUST_ERROR)
- /* An error. */
+ for (user_id = user_id_list; user_id; user_id = user_id->next)
{
- trust_level = TRUST_UNKNOWN;
- goto die;
- }
+ email = email_from_user_id (user_id->d);
- /* We do a query and then an insert. Make sure they are atomic
- by wrapping them in a transaction. */
- rc = begin_transaction (ctrl, 0);
- if (rc)
- goto die;
-
- /* If we've already seen this signature before, then don't add
- it again. */
- rc = gpgsql_stepx
- (dbs->db, &dbs->s.register_already_seen,
- get_single_unsigned_long_cb2, &c, &err,
- "select count (*)\n"
- " from signatures left join bindings\n"
- " on signatures.binding = bindings.oid\n"
- " where fingerprint = ? and email = ? and sig_time = ?\n"
- " and sig_digest = ?",
- SQLITE_ARG_STRING, fingerprint, SQLITE_ARG_STRING, email,
- SQLITE_ARG_LONG_LONG, (long long) sig_time,
- SQLITE_ARG_STRING, sig_digest,
- SQLITE_ARG_END);
- if (rc)
- {
- log_error (_("error reading TOFU database: %s\n"), err);
- print_further_info ("checking existence");
- sqlite3_free (err);
- }
- else if (c > 1)
- /* Duplicates! This should not happen. In particular,
- because <fingerprint, email, sig_time, sig_digest> is the
- primary key! */
- log_debug ("SIGNATURES DB contains duplicate records"
- " <%s, %s, 0x%lx, %s, %s>."
- " Please report.\n",
- fingerprint, email, (unsigned long) sig_time,
- sig_digest, origin);
- else if (c == 1)
- {
- already_verified = 1;
- if (DBG_TRUST)
- log_debug ("Already observed the signature"
- " <%s, %s, 0x%lx, %s, %s>\n",
- fingerprint, email, (unsigned long) sig_time,
- sig_digest, origin);
- }
- else if (opt.dry_run)
- {
- log_info ("TOFU database update skipped due to --dry-run\n");
- }
- else
- /* This is the first time that we've seen this signature.
- Record it. */
- {
if (DBG_TRUST)
- log_debug ("TOFU: Saving signature <%s, %s, %s>\n",
- fingerprint, email, sig_digest);
-
- log_assert (c == 0);
+ log_debug ("TOFU: Registering signature %s with binding"
+ " <key: %s, user id: %s>\n",
+ sig_digest, fingerprint, email);
+
+ /* Make sure the binding exists and record any TOFU
+ conflicts. */
+ if (get_trust (dbs, pk, fingerprint, email, user_id->d, 0)
+ == _tofu_GET_TRUST_ERROR)
+ {
+ rc = gpg_error (GPG_ERR_GENERAL);
+ xfree (email);
+ break;
+ }
+ /* If we've already seen this signature before, then don't add
+ it again. */
rc = gpgsql_stepx
- (dbs->db, &dbs->s.register_insert, NULL, NULL, &err,
- "insert into signatures\n"
- " (binding, sig_digest, origin, sig_time, time)\n"
- " values\n"
- " ((select oid from bindings\n"
- " where fingerprint = ? and email = ?),\n"
- " ?, ?, ?, strftime('%s', 'now'));",
- SQLITE_ARG_STRING, fingerprint, SQLITE_ARG_STRING, email,
- SQLITE_ARG_STRING, sig_digest, SQLITE_ARG_STRING, origin,
+ (dbs->db, &dbs->s.register_already_seen,
+ get_single_unsigned_long_cb2, &c, &err,
+ "select count (*)\n"
+ " from signatures left join bindings\n"
+ " on signatures.binding = bindings.oid\n"
+ " where fingerprint = ? and email = ? and sig_time = ?\n"
+ " and sig_digest = ?",
+ SQLITE_ARG_STRING, fingerprint, SQLITE_ARG_STRING, email,
SQLITE_ARG_LONG_LONG, (long long) sig_time,
+ SQLITE_ARG_STRING, sig_digest,
SQLITE_ARG_END);
if (rc)
- {
- log_error (_("error updating TOFU database: %s\n"), err);
- print_further_info ("insert signatures");
- sqlite3_free (err);
- }
+ {
+ log_error (_("error reading TOFU database: %s\n"), err);
+ print_further_info ("checking existence");
+ sqlite3_free (err);
+ }
+ else if (c > 1)
+ /* Duplicates! This should not happen. In particular,
+ because <fingerprint, email, sig_time, sig_digest> is the
+ primary key! */
+ log_debug ("SIGNATURES DB contains duplicate records"
+ " <key: %s, fingerprint: %s, time: 0x%lx, sig: %s,"
+ " origin: %s>."
+ " Please report.\n",
+ fingerprint, email, (unsigned long) sig_time,
+ sig_digest, origin);
+ else if (c == 1)
+ {
+ if (DBG_TRUST)
+ log_debug ("Already observed the signature and binding"
+ " <key: %s, user id: %s, time: 0x%lx, sig: %s,"
+ " origin: %s>\n",
+ fingerprint, email, (unsigned long) sig_time,
+ sig_digest, origin);
+ }
+ else if (opt.dry_run)
+ {
+ log_info ("TOFU database update skipped due to --dry-run\n");
+ }
+ else
+ /* This is the first time that we've seen this signature and
+ binding. Record it. */
+ {
+ if (DBG_TRUST)
+ log_debug ("TOFU: Saving signature"
+ " <key: %s, user id: %s, sig: %s>\n",
+ fingerprint, email, sig_digest);
+
+ log_assert (c == 0);
+
+ rc = gpgsql_stepx
+ (dbs->db, &dbs->s.register_insert, NULL, NULL, &err,
+ "insert into signatures\n"
+ " (binding, sig_digest, origin, sig_time, time)\n"
+ " values\n"
+ " ((select oid from bindings\n"
+ " where fingerprint = ? and email = ?),\n"
+ " ?, ?, ?, strftime('%s', 'now'));",
+ SQLITE_ARG_STRING, fingerprint, SQLITE_ARG_STRING, email,
+ SQLITE_ARG_STRING, sig_digest, SQLITE_ARG_STRING, origin,
+ SQLITE_ARG_LONG_LONG, (long long) sig_time,
+ SQLITE_ARG_END);
+ if (rc)
+ {
+ log_error (_("error updating TOFU database: %s\n"), err);
+ print_further_info ("insert signatures");
+ sqlite3_free (err);
+ }
+ }
+
+ xfree (email);
+
+ if (rc)
+ break;
}
- /* It only matters whether we abort or commit the transaction
- (so long as we do something) if we execute the insert. */
if (rc)
- rc = rollback_transaction (ctrl);
+ rollback_transaction (ctrl);
else
rc = end_transaction (ctrl, 0);
- if (rc)
- {
- sqlite3_free (err);
- goto die;
- }
- die:
- if (may_ask && trust_level != TRUST_ULTIMATE)
- /* It's only appropriate to show the statistics in an interactive
- context. */
- show_statistics (dbs, fingerprint, email, user_id,
- already_verified ? NULL : sig_digest, NULL);
-
- xfree (email);
xfree (fingerprint);
xfree (sig_digest);
- return trust_level;
+ return rc;
}
/* Combine a trust level returned from the TOFU trust model with a
@@ -2431,8 +2425,9 @@ tofu_write_tfs_record (ctrl_t ctrl, estream_t fp,
}
-/* Return the validity (TRUST_NEVER, etc.) of the binding
- <FINGERPRINT, USER_ID>.
+/* Return the validity (TRUST_NEVER, etc.) of the bindings
+ <FINGERPRINT, USER_ID>, for each USER_ID in USER_ID_LIST. If
+ USER_ID_LIST->FLAG is set, then the id is considered to be expired.
PK is the primary key packet.
@@ -2442,43 +2437,80 @@ tofu_write_tfs_record (ctrl_t ctrl, estream_t fp,
Returns TRUST_UNDEFINED if an error occurs. */
int
-tofu_get_validity (ctrl_t ctrl, PKT_public_key *pk, const char *user_id,
+tofu_get_validity (ctrl_t ctrl, PKT_public_key *pk, strlist_t user_id_list,
int may_ask)
{
tofu_dbs_t dbs;
char *fingerprint = NULL;
- char *email = NULL;
- int trust_level = TRUST_UNDEFINED;
+ strlist_t user_id;
+ int trust_level = TRUST_UNKNOWN;
dbs = opendbs (ctrl);
if (! dbs)
{
log_error (_("error opening TOFU database: %s\n"),
gpg_strerror (GPG_ERR_GENERAL));
- goto die;
+ return TRUST_UNDEFINED;
}
fingerprint = hexfingerprint (pk, NULL, 0);
- if (! *user_id)
+ begin_transaction (ctrl, 0);
+
+ for (user_id = user_id_list; user_id; user_id = user_id->next)
{
- log_debug ("user id is empty."
- " Can't get TOFU validity for this binding.\n");
- goto die;
- }
+ char *email = email_from_user_id (user_id->d);
- email = email_from_user_id (user_id);
+ /* Always call get_trust to make sure the binding is
+ registered. */
+ int tl = get_trust (dbs, pk, fingerprint, email, user_id->d, may_ask);
+ if (tl == _tofu_GET_TRUST_ERROR)
+ {
+ /* An error. */
+ trust_level = TRUST_UNDEFINED;
+ xfree (email);
+ goto die;
+ }
- trust_level = get_trust (dbs, pk, fingerprint, email, user_id, may_ask);
- if (trust_level == _tofu_GET_TRUST_ERROR)
- /* An error. */
- trust_level = TRUST_UNDEFINED;
+ if (DBG_TRUST)
+ log_debug ("TOFU: validity for <key: %s, user id: %s>: %s%s.\n",
+ fingerprint, email,
+ trust_value_to_string (tl),
+ user_id->flags ? " (but expired)" : "");
+
+ if (user_id->flags)
+ tl = TRUST_EXPIRED;
- if (may_ask && trust_level != TRUST_ULTIMATE)
- show_statistics (dbs, fingerprint, email, user_id, NULL, NULL);
+ if (may_ask && tl != TRUST_ULTIMATE && tl != TRUST_EXPIRED)
+ show_statistics (dbs, fingerprint, email, user_id->d, NULL, NULL);
+
+ if (tl == TRUST_NEVER)
+ trust_level = TRUST_NEVER;
+ else if (tl == TRUST_EXPIRED)
+ /* Ignore expired bindings in the trust calculation. */
+ ;
+ else if (tl > trust_level)
+ {
+ /* The expected values: */
+ log_assert (tl == TRUST_UNKNOWN || tl == TRUST_UNDEFINED
+ || tl == TRUST_MARGINAL || tl == TRUST_FULLY
+ || tl == TRUST_ULTIMATE);
+
+ /* We assume the following ordering: */
+ log_assert (TRUST_UNKNOWN < TRUST_UNDEFINED);
+ log_assert (TRUST_UNDEFINED < TRUST_MARGINAL);
+ log_assert (TRUST_MARGINAL < TRUST_FULLY);
+ log_assert (TRUST_FULLY < TRUST_ULTIMATE);
+
+ trust_level = tl;
+ }
+
+ xfree (email);
+ }
die:
- xfree (email);
+ end_transaction (ctrl, 0);
+
xfree (fingerprint);
return trust_level;
}
diff --git a/g10/tofu.h b/g10/tofu.h
index d6854e9..b9826c9 100644
--- a/g10/tofu.h
+++ b/g10/tofu.h
@@ -59,7 +59,7 @@ enum tofu_policy
TOFU_POLICY_ASK = 5,
- /* Privat evalue used only within tofu.c. */
+ /* Private value used only within tofu.c. */
_tofu_GET_POLICY_ERROR = 100
};
@@ -72,16 +72,19 @@ const char *tofu_policy_str (enum tofu_policy policy);
(e.g., TRUST_BAD) in light of the current configuration. */
int tofu_policy_to_trust_level (enum tofu_policy policy);
-/* Register the binding <PK, USER_ID> and the signature
- described by SIGS_DIGEST and SIG_TIME, which it generated. Origin
- describes where the signed data came from, e.g., "email:claws"
- (default: "unknown"). If MAY_ASK is 1, then this function may
- interact with the user in the case of a conflict or if the
- binding's policy is ask. This function returns the binding's trust
- level. If an error occurs, it returns TRUST_UNKNOWN. */
-int tofu_register (ctrl_t ctrl, PKT_public_key *pk, const char *user_id,
- const byte *sigs_digest, int sigs_digest_len,
- time_t sig_time, const char *origin, int may_ask);
+/* Register the bindings <PK, USER_ID>, for each USER_ID in
+ USER_ID_LIST, and the signature described by SIGS_DIGEST and
+ SIG_TIME, which it generated. Origin describes where the signed
+ data came from, e.g., "email:claws" (default: "unknown"). Note:
+ this function does not interact with the user, If there is a
+ conflict, or if the binding's policy is ask, the actual interaction
+ is deferred until tofu_get_validity is called.. Set the string
+ list FLAG to indicate that a specified user id is expired. This
+ function returns 0 on success and an error code on failure. */
+gpg_error_t tofu_register (ctrl_t ctrl, PKT_public_key *pk,
+ strlist_t user_id_list,
+ const byte *sigs_digest, int sigs_digest_len,
+ time_t sig_time, const char *origin);
/* Combine a trust level returned from the TOFU trust model with a
trust level returned by the PGP trust model. This is primarily of
@@ -92,12 +95,15 @@ int tofu_wot_trust_combine (int tofu, int wot);
gpg_error_t tofu_write_tfs_record (ctrl_t ctrl, estream_t fp,
PKT_public_key *pk, const char *user_id);
-/* Determine the validity (TRUST_NEVER, etc.) of the binding
- <PK, USER_ID>. If MAY_ASK is 1, then this function may
- interact with the user. If not, TRUST_UNKNOWN is returned. If an
- error occurs, TRUST_UNDEFINED is returned. */
+/* Determine the validity (TRUST_NEVER, etc.) of the binding <PK,
+ USER_ID>. If MAY_ASK is 1, then this function may interact with
+ the user. If not, TRUST_UNKNOWN is returned if an interaction is
+ required. Set the string list FLAGS to indicate that a specified
+ user id is expired. If an error occurs, TRUST_UNDEFINED is
+ returned. */
int tofu_get_validity (ctrl_t ctrl,
- PKT_public_key *pk, const char *user_id, int may_ask);
+ PKT_public_key *pk, strlist_t user_id_list,
+ int may_ask);
/* Set the policy for all non-revoked user ids in the keyblock KB to
POLICY. */
diff --git a/g10/trustdb.c b/g10/trustdb.c
index dd74d18..4181240 100644
--- a/g10/trustdb.c
+++ b/g10/trustdb.c
@@ -988,7 +988,7 @@ tdb_get_validity_core (ctrl_t ctrl,
int may_ask)
{
TRUSTREC trec, vrec;
- gpg_error_t err;
+ gpg_error_t err = 0;
ulong recno;
#ifdef USE_TOFU
unsigned int tofu_validity = TRUST_UNKNOWN;
@@ -1022,21 +1022,18 @@ tdb_get_validity_core (ctrl_t ctrl,
#ifdef USE_TOFU
if (opt.trust_model == TM_TOFU || opt.trust_model == TM_TOFU_PGP)
{
- kbnode_t user_id_node = NULL;
- kbnode_t n = NULL; /* Silence -Wmaybe-uninitialized. */
- int user_ids = 0;
- int user_ids_expired = 0;
+ kbnode_t kb = NULL;
+ kbnode_t n = NULL;
+ strlist_t user_id_list = NULL;
- /* If the caller didn't supply a user id then iterate over all
- uids. */
+ /* If the caller didn't supply a user id then use all uids. */
if (! uid)
- user_id_node = n = get_pubkeyblock (main_pk->keyid);
+ kb = n = get_pubkeyblock (main_pk->keyid);
- while (uid
- || (n = find_next_kbnode (n, PKT_USER_ID)))
+ while (uid || (n = find_next_kbnode (n, PKT_USER_ID)))
{
- unsigned int tl;
PKT_user_id *user_id;
+ int expired = 0;
if (uid)
user_id = uid;
@@ -1044,8 +1041,8 @@ tdb_get_validity_core (ctrl_t ctrl,
user_id = n->pkt->pkt.user_id;
/* If the user id is revoked or expired, then skip it. */
- if (user_id->is_revoked || user_id->is_expired)
- {
+ if (user_id->is_revoked || user_id->is_expired)
+ {
if (DBG_TRUST)
{
char *s;
@@ -1060,42 +1057,48 @@ tdb_get_validity_core (ctrl_t ctrl,
s, user_id->name);
}
- continue;
- }
+ if (user_id->is_revoked)
+ continue;
- user_ids ++;
+ expired = 1;
+ }
- if (sig)
- tl = tofu_register (ctrl, main_pk, user_id->name,
- sig->digest, sig->digest_len,
- sig->timestamp, "unknown",
- may_ask);
- else
- tl = tofu_get_validity (ctrl, main_pk, user_id->name, may_ask);
-
- if (tl == TRUST_EXPIRED)
- user_ids_expired ++;
- else if (tl == TRUST_UNDEFINED || tl == TRUST_UNKNOWN)
- ;
- else if (tl == TRUST_NEVER)
- tofu_validity = TRUST_NEVER;
- else
- {
- log_assert (tl == TRUST_MARGINAL
- || tl == TRUST_FULLY
- || tl == TRUST_ULTIMATE);
+ add_to_strlist (&user_id_list, user_id->name);
+ user_id_list->flags = expired;
- if (tl > tofu_validity)
- /* XXX: We we really want the max? */
- tofu_validity = tl;
- }
+ if (uid)
+ /* If the caller specified a user id, then we stop
+ now. */
+ break;
+ }
- if (uid)
- /* If the caller specified a user id, then we stop
- now. */
- break;
- }
- release_kbnode (user_id_node);
+ /* Process the user ids in the order they appear in the key
+ block. */
+ strlist_rev (&user_id_list);
+
+ /* It only makes sense to observe any signature before getting
+ the validity. This is because if the current signature
+ results in a conflict, then we damn well want to take that
+ into account. */
+ if (sig)
+ {
+ err = tofu_register (ctrl, main_pk, user_id_list,
+ sig->digest, sig->digest_len,
+ sig->timestamp, "unknown");
+ if (err)
+ {
+ log_error ("TOFU: error registering signature: %s\n",
+ gpg_strerror (err));
+
+ tofu_validity = TRUST_UNKNOWN;
+ }
+ }
+ if (! err)
+ tofu_validity = tofu_get_validity (ctrl, main_pk, user_id_list,
+ may_ask);
+
+ free_strlist (user_id_list);
+ release_kbnode (kb);
}
#endif /*USE_TOFU*/
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-gnupg/gnupg2.git
More information about the Pkg-gnupg-commit
mailing list