gpg: New option --with-tofu-info.
authorWerner Koch <wk@gnupg.org>
Thu, 25 Aug 2016 07:26:36 +0000 (09:26 +0200)
committerWerner Koch <wk@gnupg.org>
Thu, 25 Aug 2016 07:37:56 +0000 (09:37 +0200)
* g10/gpg.c (oWithTofuInfo): New.
(opts): Add --with-tofu-info.
(main): Set opt.with_tofu_info.
* g10/options.h (struct opt): Add field WITH_TOFU_INFO.
* g10/tofu.c (show_statistics): Add optional arg OUTFP and enter
special mode if not NULL.  Change all callers.
(tofu_write_tfs_record): New.
* g10/keylist.c (list_keyblock_colon): Do not print the tofu policy as
part of the "uid" record.  Print a new "tfs" record if the new option
is set.
* tests/openpgp/tofu.scm (getpolicy): Change from UID to TFS record.
--

A separate option is required to avoid slowing down key listings.
Foer example the current code takes for a keylisting in tofu+pgp mode
17 seconds while it takes more than 5 minutes if the option is used.

Signed-off-by: Werner Koch <wk@gnupg.org>
doc/DETAILS
g10/gpg.c
g10/gpgv.c
g10/keylist.c
g10/options.h
g10/test-stubs.c
g10/tofu.c
g10/tofu.h
tests/openpgp/tofu.scm

index 454f2e3..cf779d2 100644 (file)
@@ -52,7 +52,7 @@ described here.
     - sub :: Subkey (secondary key)
     - sec :: Secret key
     - ssb :: Secret subkey (secondary key)
-    - uid :: User id (only field 10 is used).
+    - uid :: User id
     - uat :: User attribute (same as user id except for field 10).
     - sig :: Signature
     - rev :: Revocation signature
@@ -214,10 +214,6 @@ described here.
 
     For pub, sub, sec, and ssb records this field is used for the ECC
     curve name.
-*** Field 18 - TOFU Policy
-
-    This is the TOFU policy.  It is either good, bad, unknown, ask or
-    auto.  This is only shows for uid records.
 
 ** Special fields
 
index e02efe4..3193e74 100644 (file)
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -193,6 +193,11 @@ enum cmd_and_opt_values
     oWithKeygrip,
     oWithSecret,
     oWithWKDHash,
+    oWithColons,
+    oWithKeyData,
+    oWithTofuInfo,
+    oWithSigList,
+    oWithSigCheck,
     oAnswerYes,
     oAnswerNo,
     oKeyring,
@@ -259,10 +264,6 @@ enum cmd_and_opt_values
     oNoOptions,
     oNoBatch,
     oHomedir,
-    oWithColons,
-    oWithKeyData,
-    oWithSigList,
-    oWithSigCheck,
     oSkipVerify,
     oSkipHiddenRecipients,
     oNoSkipHiddenRecipients,
@@ -699,6 +700,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_s (oHomedir, "homedir", "@"),
   ARGPARSE_s_n (oNoBatch, "no-batch", "@"),
   ARGPARSE_s_n (oWithColons, "with-colons", "@"),
+  ARGPARSE_s_n (oWithTofuInfo,"with-tofu-info", "@"),
   ARGPARSE_s_n (oWithKeyData,"with-key-data", "@"),
   ARGPARSE_s_n (oWithSigList,"with-sig-list", "@"),
   ARGPARSE_s_n (oWithSigCheck,"with-sig-check", "@"),
@@ -2650,6 +2652,8 @@ main (int argc, char **argv)
          case oHomedir: break;
          case oNoBatch: opt.batch = 0; break;
 
+          case oWithTofuInfo: opt.with_tofu_info = 1; break;
+
          case oWithKeyData: opt.with_key_data=1; /*FALLTHRU*/
          case oWithColons: opt.with_colons=':'; break;
 
index 4ef3e8b..1f2cecb 100644 (file)
@@ -661,6 +661,17 @@ export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options,
 }
 
 gpg_error_t
+tofu_write_tfs_record (ctrl_t ctrl, estream_t fp,
+                       PKT_public_key *pk, const char *user_id)
+{
+  (void)ctrl;
+  (void)fp;
+  (void)pk;
+  (void)user_id;
+  return gpg_error (GPG_ERR_GENERAL);
+}
+
+gpg_error_t
 tofu_get_policy (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *user_id,
                 enum tofu_policy *policy)
 {
index 59344b2..a34ef64 100644 (file)
@@ -1289,8 +1289,8 @@ list_keyblock_colon (ctrl_t ctrl, kbnode_t keyblock,
          char *str;
          PKT_user_id *uid = node->pkt->pkt.user_id;
 
-         if (attrib_fp && node->pkt->pkt.user_id->attrib_data != NULL)
-           dump_attribs (node->pkt->pkt.user_id, pk);
+         if (attrib_fp && uid->attrib_data != NULL)
+           dump_attribs (uid, pk);
          /*
           * Fixme: We need a valid flag here too
           */
@@ -1326,18 +1326,16 @@ list_keyblock_colon (ctrl_t ctrl, kbnode_t keyblock,
            es_fprintf (es_stdout, "%u %lu", uid->numattribs, uid->attrib_len);
          else
            es_write_sanitized (es_stdout, uid->name, uid->len, ":", NULL);
-         es_fprintf (es_stdout, "::::::::");
-         if (opt.trust_model == TM_TOFU || opt.trust_model == TM_TOFU_PGP)
-           {
-#ifdef USE_TOFU
-             enum tofu_policy policy;
-             if (! tofu_get_policy (ctrl, pk, uid, &policy)
-                 && policy != TOFU_POLICY_NONE)
-               es_fprintf (es_stdout, "%s", tofu_policy_str (policy));
-#endif /*USE_TOFU*/
-           }
          es_putc (':', es_stdout);
          es_putc ('\n', es_stdout);
+#ifdef USE_TOFU
+         if (!uid->attrib_data && opt.with_tofu_info
+              && (opt.trust_model == TM_TOFU || opt.trust_model == TM_TOFU_PGP))
+           {
+              /* Print a "tfs" record.  */
+              tofu_write_tfs_record (ctrl, es_stdout, pk, uid->name);
+           }
+#endif /*USE_TOFU*/
        }
       else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
        {
index 6b8f649..544be60 100644 (file)
@@ -81,6 +81,7 @@ struct
   int with_fingerprint; /* Option --with-fingerprint active.  */
   int with_subkey_fingerprint; /* Option --with-subkey-fingerprint active.  */
   int with_keygrip;     /* Option --with-keygrip active.  */
+  int with_tofu_info;   /* Option --with-tofu_info active.  */
   int with_secret;      /* Option --with-secret active.  */
   int with_wkd_hash;    /* Option --with-wkd-hash.  */
   int fingerprint; /* list fingerprints */
index c5f2f79..55351b8 100644 (file)
@@ -474,6 +474,17 @@ export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options,
 }
 
 gpg_error_t
+tofu_write_tfs_record (ctrl_t ctrl, estream_t fp,
+                       PKT_public_key *pk, const char *user_id)
+{
+  (void)ctrl;
+  (void)fp;
+  (void)pk;
+  (void)user_id;
+  return gpg_error (GPG_ERR_GENERAL);
+}
+
+gpg_error_t
 tofu_get_policy (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *user_id,
                 enum tofu_policy *policy)
 {
index 29318c7..9d562c2 100644 (file)
@@ -1919,10 +1919,13 @@ write_stats_status (estream_t fp, long messages, enum tofu_policy policy,
     }
 }
 
+
+/* Note: If OUTFP is not NULL, this function merely prints a "tfs" record
+ * to OUTFP.  In this case USER_ID is not required.  */
 static void
 show_statistics (tofu_dbs_t dbs, const char *fingerprint,
                 const char *email, const char *user_id,
-                const char *sig_exclude)
+                const char *sig_exclude, estream_t outfp)
 {
   char *fingerprint_pp;
   int rc;
@@ -1951,15 +1954,16 @@ show_statistics (tofu_dbs_t dbs, const char *fingerprint,
       goto out;
     }
 
-
-  write_status_text_and_buffer (STATUS_TOFU_USER, fingerprint,
-                                email, strlen (email), 0);
+  if (!outfp)
+    write_status_text_and_buffer (STATUS_TOFU_USER, fingerprint,
+                                  email, strlen (email), 0);
 
   if (! strlist)
     {
-      log_info (_("Have never verified a message signed by key %s!\n"),
-                fingerprint_pp);
-      write_stats_status (NULL, 0, TOFU_POLICY_NONE, 0, 0);
+      if (!outfp)
+        log_info (_("Have never verified a message signed by key %s!\n"),
+                  fingerprint_pp);
+      write_stats_status (outfp, 0, TOFU_POLICY_NONE, 0, 0);
     }
   else
     {
@@ -1999,10 +2003,17 @@ show_statistics (tofu_dbs_t dbs, const char *fingerprint,
 
       if (messages == -1 || !first_seen)
         {
-          write_stats_status (NULL, 0, TOFU_POLICY_NONE, 0, 0);
-          log_info (_("Failed to collect signature statistics for \"%s\"\n"
-                      "(key %s)\n"),
-                    user_id, fingerprint_pp);
+          write_stats_status (outfp, 0, TOFU_POLICY_NONE, 0, 0);
+          if (!outfp)
+            log_info (_("Failed to collect signature statistics for \"%s\"\n"
+                        "(key %s)\n"),
+                      user_id, fingerprint_pp);
+        }
+      else if (outfp)
+        {
+          write_stats_status (outfp, messages,
+                              get_policy (dbs, fingerprint, email, NULL),
+                              first_seen, most_recent_seen);
         }
       else
        {
@@ -2010,7 +2021,8 @@ show_statistics (tofu_dbs_t dbs, const char *fingerprint,
          estream_t fp;
          char *msg;
 
-          write_stats_status (NULL, messages, policy,
+          write_stats_status (NULL, messages,
+                              policy,
                               first_seen, most_recent_seen);
 
          fp = es_fopenmem (0, "rw,samethread");
@@ -2313,7 +2325,7 @@ tofu_register (ctrl_t ctrl, PKT_public_key *pk, const char *user_id,
     /* It's only appropriate to show the statistics in an interactive
        context.  */
     show_statistics (dbs, fingerprint, email, user_id,
-                    already_verified ? NULL : sig_digest);
+                    already_verified ? NULL : sig_digest, NULL);
 
   xfree (email);
   xfree (fingerprint);
@@ -2385,6 +2397,38 @@ tofu_wot_trust_combine (int tofu_base, int wot_base)
 }
 
 
+/* Write a "tfs" record for a --with-colons listing.  */
+gpg_error_t
+tofu_write_tfs_record (ctrl_t ctrl, estream_t fp,
+                       PKT_public_key *pk, const char *user_id)
+{
+  gpg_error_t err;
+  tofu_dbs_t dbs;
+  char *fingerprint;
+  char *email;
+
+  if (!*user_id)
+    return 0;  /* No TOFU stats possible for an empty ID.  */
+
+  dbs = opendbs (ctrl);
+  if (!dbs)
+    {
+      err = gpg_error (GPG_ERR_GENERAL);
+      log_error (_("error opening TOFU database: %s\n"), gpg_strerror (err));
+      return err;
+    }
+
+  fingerprint = hexfingerprint (pk, NULL, 0);
+  email = email_from_user_id (user_id);
+
+  show_statistics (dbs, fingerprint, email, user_id, NULL, fp);
+
+  xfree (email);
+  xfree (fingerprint);
+  return 0;
+}
+
+
 /* Return the validity (TRUST_NEVER, etc.) of the binding
    <FINGERPRINT, USER_ID>.
 
@@ -2429,7 +2473,7 @@ tofu_get_validity (ctrl_t ctrl, PKT_public_key *pk, const char *user_id,
     trust_level = TRUST_UNDEFINED;
 
   if (may_ask && trust_level != TRUST_ULTIMATE)
-    show_statistics (dbs, fingerprint, email, user_id, NULL);
+    show_statistics (dbs, fingerprint, email, user_id, NULL, NULL);
 
  die:
   xfree (email);
index e3ec819..d6854e9 100644 (file)
@@ -88,6 +88,10 @@ int tofu_register (ctrl_t ctrl, PKT_public_key *pk, const char *user_id,
    interest when the trust model is tofu+pgp (TM_TOFU_PGP).  */
 int tofu_wot_trust_combine (int tofu, int wot);
 
+/* Write a "tfs" record for a --with-colons listing.  */
+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
index 2b302ba..448c253 100755 (executable)
 ;; This function only supports keys with a single user id.
 (define (getpolicy keyid format . args)
   (let ((policy
-        (list-ref (assoc "uid" (gpg-with-colons
+        (list-ref (assoc "tfs" (gpg-with-colons
                                 `(--tofu-db-format ,format
-                                  --trust-model=tofu
+                                  --trust-model=tofu --with-tofu-info
                                   ,@args
-                                  --list-keys ,keyid))) 17)))
+                                  --list-keys ,keyid))) 5)))
     (unless (member policy '("auto" "good" "unknown" "bad" "ask"))
            (error "Bad policy:" policy))
     policy))