gpg: New option --with-tofu-info.

* 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>
This commit is contained in:
Werner Koch 2016-08-25 09:26:36 +02:00
parent 0f1f02acc1
commit 19d12be3ce
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
9 changed files with 107 additions and 38 deletions

View 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

View File

@ -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;

View File

@ -660,6 +660,17 @@ export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options,
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
}
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)

View 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)
{

View 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 */

View File

@ -473,6 +473,17 @@ export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options,
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
}
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)

View 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);

View 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

View File

@ -46,11 +46,11 @@
;; 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))