core: Add GPGME_KEYLIST_MODE_WITH_TOFU.
* src/gpgme.h.in (GPGME_KEYLIST_MODE_WITH_TOFU): New. * src/engine-gpg.c (gpg_keylist_build_options): Use that. * src/keylist.c: Include limits.h. (parse_tfs_record): New. (keylist_colon_handler): Support TFS record. * tests/run-keylist.c: Include time.h. (isotimestr): New. (main): Add option --tofu. Print TOFU info. * tests/run-verify.c: Include time.h. (isotimestr): New. (print_result): Use isotimestr for TOFU dates. Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
38798fee5b
commit
9ee103957e
1
NEWS
1
NEWS
@ -26,6 +26,7 @@ Noteworthy changes in version 1.7.0 (unreleased) [C25/A14/R_]
|
||||
GPGME_STATUS_TOFU_STATS NEW.
|
||||
GPGME_STATUS_TOFU_STATS_LONG NEW.
|
||||
GPGME_STATUS_NOTATION_FLAGS NEW.
|
||||
GPGME_KEYLIST_MODE_WITH_TOFU NEW.
|
||||
GPGME_DATA_TYPE_PGP_ENCRYPTED NEW.
|
||||
GPGME_DATA_TYPE_PGP_SIGNATURE NEW.
|
||||
GPGME_DATA_ENCODING_MIME NEW.
|
||||
|
@ -2683,6 +2683,11 @@ signature notations on key signatures should be included in the listed
|
||||
keys. This only works if @code{GPGME_KEYLIST_MODE_SIGS} is also
|
||||
enabled.
|
||||
|
||||
@item GPGME_KEYLIST_MODE_WITH_TOFU
|
||||
The @code{GPGME_KEYLIST_MODE_WITH_TOFU} symbol specifies that
|
||||
information pertaining to the TOFU trust model should be included in
|
||||
the listed keys.
|
||||
|
||||
@item GPGME_KEYLIST_MODE_WITH_SECRET
|
||||
The @code{GPGME_KEYLIST_MODE_WITH_SECRET} returns information about
|
||||
the presence of a corresponding secret key in a public key listing. A
|
||||
|
@ -2338,8 +2338,13 @@ gpg_keylist_build_options (engine_gpg_t gpg, int secret_only,
|
||||
err = add_arg (gpg, "--with-fingerprint");
|
||||
}
|
||||
|
||||
if (!err && (mode & GPGME_KEYLIST_MODE_WITH_TOFU)
|
||||
&& have_gpg_version (gpg, "2.1.16"))
|
||||
err = add_arg (gpg, "--with-tofu-info");
|
||||
|
||||
if (!err && (mode & GPGME_KEYLIST_MODE_WITH_SECRET))
|
||||
err = add_arg (gpg, "--with-secret");
|
||||
|
||||
if (!err
|
||||
&& (mode & GPGME_KEYLIST_MODE_SIGS)
|
||||
&& (mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS))
|
||||
@ -2348,6 +2353,7 @@ gpg_keylist_build_options (engine_gpg_t gpg, int secret_only,
|
||||
if (!err)
|
||||
err = add_arg (gpg, "show-sig-subpackets=\"20,26\"");
|
||||
}
|
||||
|
||||
if (!err)
|
||||
{
|
||||
if ( (mode & GPGME_KEYLIST_MODE_EXTERN) )
|
||||
@ -2379,6 +2385,7 @@ gpg_keylist_build_options (engine_gpg_t gpg, int secret_only,
|
||||
? "--check-sigs" : "--list-keys"));
|
||||
}
|
||||
}
|
||||
|
||||
if (!err)
|
||||
err = add_arg (gpg, "--");
|
||||
|
||||
|
@ -411,6 +411,7 @@ gpgme_protocol_t;
|
||||
#define GPGME_KEYLIST_MODE_SIGS 4
|
||||
#define GPGME_KEYLIST_MODE_SIG_NOTATIONS 8
|
||||
#define GPGME_KEYLIST_MODE_WITH_SECRET 16
|
||||
#define GPGME_KEYLIST_MODE_WITH_TOFU 32
|
||||
#define GPGME_KEYLIST_MODE_EPHEMERAL 128
|
||||
#define GPGME_KEYLIST_MODE_VALIDATE 256
|
||||
|
||||
@ -843,7 +844,7 @@ struct _gpgme_user_id
|
||||
* NULL is stored. */
|
||||
char *address;
|
||||
|
||||
/* The malloced tofo information or NULL. */
|
||||
/* The malloced TOFU information or NULL. */
|
||||
gpgme_tofu_info_t tofu;
|
||||
};
|
||||
typedef struct _gpgme_user_id *gpgme_user_id_t;
|
||||
|
100
src/keylist.c
100
src/keylist.c
@ -33,6 +33,7 @@
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
/* Suppress warning for accessing deprecated member "class". */
|
||||
#define _GPGME_IN_GPGME
|
||||
@ -403,6 +404,84 @@ parse_sec_field15 (gpgme_key_t key, gpgme_subkey_t subkey, char *field)
|
||||
}
|
||||
|
||||
|
||||
/* Parse a tfs record. */
|
||||
static gpg_error_t
|
||||
parse_tfs_record (gpgme_user_id_t uid, char **field, int nfield)
|
||||
{
|
||||
gpg_error_t err;
|
||||
gpgme_tofu_info_t ti;
|
||||
unsigned long uval;
|
||||
|
||||
/* We add only the first TOFU record in case future versions emit
|
||||
* several. */
|
||||
if (uid->tofu)
|
||||
return 0;
|
||||
|
||||
/* Check that we have enough fields and that the version is supported. */
|
||||
if (nfield < 8 || atoi(field[1]) != 1)
|
||||
return trace_gpg_error (GPG_ERR_INV_ENGINE);
|
||||
|
||||
ti = calloc (1, sizeof *ti);
|
||||
if (!ti)
|
||||
return gpg_error_from_syserror ();
|
||||
|
||||
/* Note that we allow a value of up to 7 which is what we can store
|
||||
* in the ti->validity. */
|
||||
err = _gpgme_strtoul_field (field[2], &uval);
|
||||
if (err || uval > 7)
|
||||
goto inv_engine;
|
||||
ti->validity = uval;
|
||||
|
||||
/* Parse the sign-count. */
|
||||
err = _gpgme_strtoul_field (field[3], &uval);
|
||||
if (err)
|
||||
goto inv_engine;
|
||||
if (uval > USHRT_MAX)
|
||||
uval = USHRT_MAX;
|
||||
ti->signcount = uval;
|
||||
|
||||
/* Parse the encr-count. */
|
||||
err = _gpgme_strtoul_field (field[4], &uval);
|
||||
if (err)
|
||||
goto inv_engine;
|
||||
if (uval > USHRT_MAX)
|
||||
uval = USHRT_MAX;
|
||||
ti->encrcount = uval;
|
||||
|
||||
/* Parse the policy. */
|
||||
if (!strcmp (field[5], "none"))
|
||||
ti->policy = GPGME_TOFU_POLICY_NONE;
|
||||
else if (!strcmp (field[5], "auto"))
|
||||
ti->policy = GPGME_TOFU_POLICY_AUTO;
|
||||
else if (!strcmp (field[5], "good"))
|
||||
ti->policy = GPGME_TOFU_POLICY_GOOD;
|
||||
else if (!strcmp (field[5], "bad"))
|
||||
ti->policy = GPGME_TOFU_POLICY_BAD;
|
||||
else if (!strcmp (field[5], "ask"))
|
||||
ti->policy = GPGME_TOFU_POLICY_ASK;
|
||||
else /* "unknown" and invalid policy strings. */
|
||||
ti->policy = GPGME_TOFU_POLICY_UNKNOWN;
|
||||
|
||||
/* Parse first and last seen timestamps. */
|
||||
err = _gpgme_strtoul_field (field[6], &uval);
|
||||
if (err)
|
||||
goto inv_engine;
|
||||
ti->firstseen = uval;
|
||||
err = _gpgme_strtoul_field (field[7], &uval);
|
||||
if (err)
|
||||
goto inv_engine;
|
||||
ti->lastseen = uval;
|
||||
|
||||
/* Ready. */
|
||||
uid->tofu = ti;
|
||||
return 0;
|
||||
|
||||
inv_engine:
|
||||
free (ti);
|
||||
return trace_gpg_error (GPG_ERR_INV_ENGINE);
|
||||
}
|
||||
|
||||
|
||||
/* We have read an entire key into tmp_key and should now finish it.
|
||||
It is assumed that this releases tmp_key. */
|
||||
static void
|
||||
@ -426,7 +505,7 @@ keylist_colon_handler (void *priv, char *line)
|
||||
gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
|
||||
enum
|
||||
{
|
||||
RT_NONE, RT_SIG, RT_UID, RT_SUB, RT_PUB, RT_FPR, RT_GRP,
|
||||
RT_NONE, RT_SIG, RT_UID, RT_TFS, RT_SUB, RT_PUB, RT_FPR, RT_GRP,
|
||||
RT_SSB, RT_SEC, RT_CRT, RT_CRS, RT_REV, RT_SPK
|
||||
}
|
||||
rectype = RT_NONE;
|
||||
@ -483,6 +562,8 @@ keylist_colon_handler (void *priv, char *line)
|
||||
rectype = RT_GRP;
|
||||
else if (!strcmp (field[0], "uid") && key)
|
||||
rectype = RT_UID;
|
||||
else if (!strcmp (field[0], "tfs") && key)
|
||||
rectype = RT_TFS;
|
||||
else if (!strcmp (field[0], "sub") && key)
|
||||
rectype = RT_SUB;
|
||||
else if (!strcmp (field[0], "ssb") && key)
|
||||
@ -492,10 +573,10 @@ keylist_colon_handler (void *priv, char *line)
|
||||
else
|
||||
rectype = RT_NONE;
|
||||
|
||||
/* Only look at signatures immediately following a user ID. For
|
||||
this, clear the user ID pointer when encountering anything but a
|
||||
signature. */
|
||||
if (rectype != RT_SIG && rectype != RT_REV)
|
||||
/* Only look at signature and trust info records immediately
|
||||
following a user ID. For this, clear the user ID pointer when
|
||||
encountering anything but a signature or trust record. */
|
||||
if (rectype != RT_SIG && rectype != RT_REV && rectype != RT_TFS)
|
||||
opd->tmp_uid = NULL;
|
||||
|
||||
/* Only look at subpackets immediately following a signature. For
|
||||
@ -695,6 +776,15 @@ keylist_colon_handler (void *priv, char *line)
|
||||
}
|
||||
break;
|
||||
|
||||
case RT_TFS:
|
||||
if (opd->tmp_uid)
|
||||
{
|
||||
err = parse_tfs_record (opd->tmp_uid, field, fields);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
|
||||
case RT_FPR:
|
||||
/* Field 10 has the fingerprint (take only the first one). */
|
||||
if (fields >= 10 && field[9] && *field[9])
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <gpgme.h>
|
||||
|
||||
@ -49,6 +50,7 @@ show_usage (int ex)
|
||||
" --local use GPGME_KEYLIST_MODE_LOCAL\n"
|
||||
" --extern use GPGME_KEYLIST_MODE_EXTERN\n"
|
||||
" --sigs use GPGME_KEYLIST_MODE_SIGS\n"
|
||||
" --tofu use GPGME_KEYLIST_MODE_TOFU\n"
|
||||
" --sig-notations use GPGME_KEYLIST_MODE_SIG_NOTATIONS\n"
|
||||
" --ephemeral use GPGME_KEYLIST_MODE_EPHEMERAL\n"
|
||||
" --validate use GPGME_KEYLIST_MODE_VALIDATE\n"
|
||||
@ -60,6 +62,26 @@ show_usage (int ex)
|
||||
}
|
||||
|
||||
|
||||
static const char *
|
||||
isotimestr (unsigned long value)
|
||||
{
|
||||
time_t t;
|
||||
static char buffer[25+5];
|
||||
struct tm *tp;
|
||||
|
||||
if (!value)
|
||||
return "none";
|
||||
t = value;
|
||||
|
||||
tp = gmtime (&t);
|
||||
snprintf (buffer, sizeof buffer, "%04d-%02d-%02d %02d:%02d:%02d",
|
||||
1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
|
||||
tp->tm_hour, tp->tm_min, tp->tm_sec);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
@ -120,6 +142,11 @@ main (int argc, char **argv)
|
||||
mode |= GPGME_KEYLIST_MODE_EXTERN;
|
||||
argc--; argv++;
|
||||
}
|
||||
else if (!strcmp (*argv, "--tofu"))
|
||||
{
|
||||
mode |= GPGME_KEYLIST_MODE_WITH_TOFU;
|
||||
argc--; argv++;
|
||||
}
|
||||
else if (!strcmp (*argv, "--sigs"))
|
||||
{
|
||||
mode |= GPGME_KEYLIST_MODE_SIGS;
|
||||
@ -181,6 +208,7 @@ main (int argc, char **argv)
|
||||
while (!(err = gpgme_op_keylist_next (ctx, &key)))
|
||||
{
|
||||
gpgme_user_id_t uid;
|
||||
gpgme_tofu_info_t ti;
|
||||
int nuids;
|
||||
int nsub;
|
||||
|
||||
@ -233,23 +261,41 @@ main (int argc, char **argv)
|
||||
for (nuids=0, uid=key->uids; uid; uid = uid->next, nuids++)
|
||||
{
|
||||
printf ("userid %d: %s\n", nuids, nonnull(uid->uid));
|
||||
printf (" mbox %d: %s\n", nuids, nonnull(uid->address));
|
||||
printf (" mbox: %s\n", nonnull(uid->address));
|
||||
if (uid->email && uid->email != uid->address)
|
||||
printf (" email %d: %s\n", nuids, uid->email);
|
||||
printf (" email: %s\n", uid->email);
|
||||
if (uid->name)
|
||||
printf (" name %d: %s\n", nuids, uid->name);
|
||||
printf (" name: %s\n", uid->name);
|
||||
if (uid->comment)
|
||||
printf (" cmmnt %d: %s\n", nuids, uid->comment);
|
||||
printf (" valid %d: %s\n", nuids,
|
||||
printf (" cmmnt: %s\n", uid->comment);
|
||||
printf (" valid: %s\n",
|
||||
uid->validity == GPGME_VALIDITY_UNKNOWN? "unknown":
|
||||
uid->validity == GPGME_VALIDITY_UNDEFINED? "undefined":
|
||||
uid->validity == GPGME_VALIDITY_NEVER? "never":
|
||||
uid->validity == GPGME_VALIDITY_MARGINAL? "marginal":
|
||||
uid->validity == GPGME_VALIDITY_FULL? "full":
|
||||
uid->validity == GPGME_VALIDITY_ULTIMATE? "ultimate": "[?]");
|
||||
if ((ti = uid->tofu))
|
||||
{
|
||||
printf (" tofu: %u (%s)\n", ti->validity,
|
||||
ti->validity == 0? "conflict" :
|
||||
ti->validity == 1? "no history" :
|
||||
ti->validity == 2? "little history" :
|
||||
ti->validity == 3? "enough history" :
|
||||
ti->validity == 4? "lot of history" : "?");
|
||||
printf (" policy: %u (%s)\n", ti->policy,
|
||||
ti->policy == GPGME_TOFU_POLICY_NONE? "none" :
|
||||
ti->policy == GPGME_TOFU_POLICY_AUTO? "auto" :
|
||||
ti->policy == GPGME_TOFU_POLICY_GOOD? "good" :
|
||||
ti->policy == GPGME_TOFU_POLICY_UNKNOWN? "unknown" :
|
||||
ti->policy == GPGME_TOFU_POLICY_BAD? "bad" :
|
||||
ti->policy == GPGME_TOFU_POLICY_ASK? "ask" : "?");
|
||||
printf (" nsigs: %hu\n", ti->signcount);
|
||||
printf (" nencr: %hu\n", ti->encrcount);
|
||||
printf (" first: %s\n", isotimestr (ti->firstseen));
|
||||
printf (" last: %s\n", isotimestr (ti->lastseen));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
putchar ('\n');
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <gpgme.h>
|
||||
|
||||
@ -36,6 +37,26 @@
|
||||
|
||||
static int verbose;
|
||||
|
||||
|
||||
static const char *
|
||||
isotimestr (unsigned long value)
|
||||
{
|
||||
time_t t;
|
||||
static char buffer[25+5];
|
||||
struct tm *tp;
|
||||
|
||||
if (!value)
|
||||
return "none";
|
||||
t = value;
|
||||
|
||||
tp = gmtime (&t);
|
||||
snprintf (buffer, sizeof buffer, "%04d-%02d-%02d %02d:%02d:%02d",
|
||||
1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
|
||||
tp->tm_hour, tp->tm_min, tp->tm_sec);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
status_cb (void *opaque, const char *keyword, const char *value)
|
||||
{
|
||||
@ -177,8 +198,8 @@ print_result (gpgme_verify_result_t result)
|
||||
ti->policy == GPGME_TOFU_POLICY_BAD? "bad" :
|
||||
ti->policy == GPGME_TOFU_POLICY_ASK? "ask" : "?");
|
||||
printf (" sigcount : %hu\n", ti->signcount);
|
||||
printf (" firstseen: %u\n", ti->firstseen);
|
||||
printf (" lastseen : %u\n", ti->lastseen);
|
||||
printf (" firstseen: %s\n", isotimestr (ti->firstseen));
|
||||
printf (" lastseen : %s\n", isotimestr (ti->lastseen));
|
||||
printf (" desc ....: ");
|
||||
print_description (nonnull (ti->description), 15);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user