diff options
| author | Werner Koch <[email protected]> | 2016-08-25 09:38:03 +0000 | 
|---|---|---|
| committer | Werner Koch <[email protected]> | 2016-08-25 09:38:03 +0000 | 
| commit | 9ee103957e4136337b92d238283f8ef30fd4a7c5 (patch) | |
| tree | 28efd68346717ec611619c22bc9f3799f44d29bf | |
| parent | core: Adjust for TOFU_STATS change in gnupg 2.1.16. (diff) | |
| download | gpgme-9ee103957e4136337b92d238283f8ef30fd4a7c5.tar.gz gpgme-9ee103957e4136337b92d238283f8ef30fd4a7c5.zip | |
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 <[email protected]>
| -rw-r--r-- | NEWS | 1 | ||||
| -rw-r--r-- | doc/gpgme.texi | 5 | ||||
| -rw-r--r-- | src/engine-gpg.c | 7 | ||||
| -rw-r--r-- | src/gpgme.h.in | 3 | ||||
| -rw-r--r-- | src/keylist.c | 100 | ||||
| -rw-r--r-- | tests/run-keylist.c | 60 | ||||
| -rw-r--r-- | tests/run-verify.c | 25 | 
7 files changed, 186 insertions, 15 deletions
| @@ -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. diff --git a/doc/gpgme.texi b/doc/gpgme.texi index 02551d98..dfc9548b 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -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 diff --git a/src/engine-gpg.c b/src/engine-gpg.c index 3edac6ca..7036ee08 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -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, "--"); diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 79a7b9fd..57f34469 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -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; diff --git a/src/keylist.c b/src/keylist.c index 38ddd0c5..9f1e68db 100644 --- a/src/keylist.c +++ b/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]) diff --git a/tests/run-keylist.c b/tests/run-keylist.c index bae2dbb9..00f874da 100644 --- a/tests/run-keylist.c +++ b/tests/run-keylist.c @@ -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,24 +261,42 @@ 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');        if (import) diff --git a/tests/run-verify.c b/tests/run-verify.c index ef4dd32e..3c18d3b6 100644 --- a/tests/run-verify.c +++ b/tests/run-verify.c @@ -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);              } | 
