Handling a TOFU conflict

Neal H. Walfield neal at walfield.org
Wed Dec 7 10:26:00 CET 2016


Attached is a minimal patch that implements the TOFU_USER/TOFU_STATS
functionality.  It is preceded by example output.

Personally, I'd prefer to combine the TOFU_USER and TOFU_STATS lines
to make it more context free.  But, given how much output is currently
not context free, it's not a priority.

One could also imagine emitting another status line at the beginning
indicating that a conflict has been detected.  This would probably
make it easier for parsers, since they know why the TOFU_USER and
TOFU_STATS status lines are being emitted.

Should I do any of these things?  Should I commit as it?  Or, should I
leave it the way it currently is?

Thanks!

:) Neal

$ gpg --command-fd 0 --status-fd 1 --trust-model tofu -r 16045E5FD8572D7C44AA6DCECC8D32F31C005AF3 -e 
gpg: NOTE: THIS IS A DEVELOPMENT VERSION!
gpg: It is only intended for test purposes and should NOT be
gpg: used in a production environment or with production keys!
[GNUPG:] KEY_CONSIDERED 16045E5FD8572D7C44AA6DCECC8D32F31C005AF3 0
[GNUPG:] KEY_CONSIDERED 16045E5FD8572D7C44AA6DCECC8D32F31C005AF3 0
[GNUPG:] KEY_CONSIDERED 16045E5FD8572D7C44AA6DCECC8D32F31C005AF3 0
[GNUPG:] KEY_CONSIDERED 16045E5FD8572D7C44AA6DCECC8D32F31C005AF3 0
[GNUPG:] TOFU_USER 16045E5FD8572D7C44AA6DCECC8D32F31C005AF3 joke.factory at example.com
[GNUPG:] TOFU_STATS 0 0 0 ask 0 0 0 0 1
[GNUPG:] TOFU_USER 6F343BADCC2ABE3C5A2E295B2A16A78FB662E42F joke.factory at example.com
[GNUPG:] TOFU_STATS 0 0 0 ask 0 0 0 0 1
[GNUPG:] TOFU_USER 97D68CB9B03F8137EB884940EE7C7DA4BE04EB2B joke.factory at example.com
[GNUPG:] TOFU_STATS 0 0 0 ask 0 0 0 0 1
The email address "joke.factory at example.com" is associated with 3 keys!
Please indicate whether this email address should be associated with key
16045E5FD8572D7C44AA6DCECC8D32F31C005AF3 or whether you think someone is
impersonating "joke.factory at example.com".

This key's user IDs:
  Joke Factory <joke.factory at example.com> (policy: auto)

Statistics for keys with the email address "joke.factory at example.com":
  1604 5E5F D857 2D7C 44AA  6DCE CC8D 32F3 1C00 5AF3 (this key):
    Encrypted 0 messages.
    Verified 0 messages.
  6F34 3BAD CC2A BE3C 5A2E  295B 2A16 A78F B662 E42F (policy: auto):
    Encrypted 0 messages.
    Verified 0 messages.
  97D6 8CB9 B03F 8137 EB88  4940 EE7C 7DA4 BE04 EB2B (policy: auto):
    Encrypted 0 messages.
    Verified 0 messages.

Normally, an email address is associated with a single key.  However,
people sometimes generate a new key if their key is too old or they think
it might be compromised.  Alternatively, a new key may indicate a
man-in-the-middle attack!  Before accepting this association, you should
talk to or call the person to make sure this new key is legitimate.

[GNUPG:] GET_LINE tofu.conflict


From 89b147be248c989eee1d7996a2c55ae4f0bd6ac9 Mon Sep 17 00:00:00 2001
From: "Neal H. Walfield" <neal at g10code.com>
Date: Wed, 7 Dec 2016 10:11:46 +0100
Subject: [PATCH] g10: On a TOFU conflict, write the conflicting keys to the
 status fd

* g10/tofu.c (ask_about_binding): Emit all of the conflicting keys and
their statistics on the status fd.
(show_statistics): Have the caller pass the policy as returned by
get_policy.  Add argument only_status_fd and don't emit any output on
stdout if it is set.  Update callers.

--
Signed-off-by: Neal H. Walfield <neal at g10code.com>
---
 g10/tofu.c | 44 +++++++++++++++++++++++++++++---------------
 1 file changed, 29 insertions(+), 15 deletions(-)

diff --git a/g10/tofu.c b/g10/tofu.c
index 5b3e84c..5906bfa 100644
--- a/g10/tofu.c
+++ b/g10/tofu.c
@@ -112,8 +112,10 @@ struct tofu_dbs_s
 /* Local prototypes.  */
 static gpg_error_t end_transaction (ctrl_t ctrl, int only_batch);
 static char *email_from_user_id (const char *user_id);
-
-
+static int show_statistics (tofu_dbs_t dbs,
+                            const char *fingerprint, const char *email,
+                            enum tofu_policy policy,
+                            estream_t outfp, int only_status_fd, time_t now);
 
 const char *
 tofu_policy_str (enum tofu_policy policy)
@@ -1797,6 +1799,9 @@ ask_about_binding (ctrl_t ctrl,
               xfree (key_pp);
 
               seen_in_past = 0;
+
+              show_statistics (dbs, stats_iter->fingerprint, email,
+                               TOFU_POLICY_ASK, NULL, 1, now);
             }
 
           if (labs(stats_iter->time_ago) == 1)
@@ -2913,17 +2918,18 @@ write_stats_status (estream_t fp,
 /* Note: If OUTFP is not NULL, this function merely prints a "tfs" record
  * to OUTFP.
  *
- * Returns whether the caller should call show_warning after iterating
- * over all user ids.
+ * POLICY is the key's policy (as returned by get_policy).
+ *
+ * Returns 0 if if ONLY_STATUS_FD is set.  Otherwise, returns whether
+ * the caller should call show_warning after iterating over all user
+ * ids.
  */
 static int
-show_statistics (tofu_dbs_t dbs, PKT_public_key *pk, const char *fingerprint,
-		 const char *email, const char *user_id,
-		 estream_t outfp, time_t now)
+show_statistics (tofu_dbs_t dbs,
+                 const char *fingerprint, const char *email,
+                 enum tofu_policy policy,
+		 estream_t outfp, int only_status_fd, time_t now)
 {
-  enum tofu_policy policy =
-    get_policy (dbs, pk, fingerprint, user_id, email, NULL, now);
-
   char *fingerprint_pp;
   int rc;
   strlist_t strlist = NULL;
@@ -2938,7 +2944,8 @@ show_statistics (tofu_dbs_t dbs, PKT_public_key *pk, const char *fingerprint,
 
   int show_warning = 0;
 
-  (void) user_id;
+  if (only_status_fd && ! is_status_enabled ())
+    return 0;
 
   fingerprint_pp = format_hexfingerprint (fingerprint, NULL, 0);
 
@@ -3020,7 +3027,7 @@ show_statistics (tofu_dbs_t dbs, PKT_public_key *pk, const char *fingerprint,
                       encryption_first_done,
                       encryption_most_recent);
 
-  if (!outfp)
+  if (!outfp && !only_status_fd)
     {
       estream_t fp;
       char *msg;
@@ -3548,6 +3555,7 @@ tofu_write_tfs_record (ctrl_t ctrl, estream_t fp,
   tofu_dbs_t dbs;
   char *fingerprint;
   char *email;
+  enum tofu_policy policy;
 
   if (!*user_id)
     return 0;  /* No TOFU stats possible for an empty ID.  */
@@ -3562,8 +3570,9 @@ tofu_write_tfs_record (ctrl_t ctrl, estream_t fp,
 
   fingerprint = hexfingerprint (pk, NULL, 0);
   email = email_from_user_id (user_id);
+  policy = get_policy (dbs, pk, fingerprint, user_id, email, NULL, now);
 
-  show_statistics (dbs, pk, fingerprint, email, user_id, fp, now);
+  show_statistics (dbs, fingerprint, email, policy, fp, 0, now);
 
   xfree (email);
   xfree (fingerprint);
@@ -3638,8 +3647,13 @@ tofu_get_validity (ctrl_t ctrl, PKT_public_key *pk, strlist_t user_id_list,
         bindings_valid ++;
 
       if (may_ask && tl != TRUST_ULTIMATE && tl != TRUST_EXPIRED)
-        need_warning |=
-          show_statistics (dbs, pk, fingerprint, email, user_id->d, NULL, now);
+        {
+          enum tofu_policy policy =
+            get_policy (dbs, pk, fingerprint, user_id->d, email, NULL, now);
+
+          need_warning |=
+            show_statistics (dbs, fingerprint, email, policy, NULL, 0, now);
+        }
 
       if (tl == TRUST_NEVER)
         trust_level = TRUST_NEVER;
-- 
2.1.4




More information about the Gnupg-devel mailing list