[git] GPGME - branch, master, updated. gpgme-1.6.0-124-g10df06e

by Werner Koch cvs at cvs.gnupg.org
Sat May 21 10:34:14 CEST 2016


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GnuPG Made Easy".

The branch, master has been updated
       via  10df06ee8f9192309bf124872438f7c32457e1c6 (commit)
       via  dac2c5441d418536632f014c8b0e1359580279d1 (commit)
       via  a92946a8cacc44f655249d84b316deae59e62671 (commit)
      from  eaf2d018e63c15cd9a81e5c1fd2fedbf8829f7b9 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 10df06ee8f9192309bf124872438f7c32457e1c6
Author: Werner Koch <wk at gnupg.org>
Date:   Sat May 21 10:29:49 2016 +0200

    api: Return Tofu info for signatures.
    
    * src/gpgme.h.in (gpgme_tofu_policy_t): New.
    (gpgme_status_code_t): Add status codes for TOFU.
    (struct _gpgme_tofu_info, gpgme_tofu_info_t): New.
    (struct _gpgme_signature): Add field 'tofu'.
    * src/status-table.c (status_table): Add new codes.
    * src/verify.c: Include limits.h.
    (release_tofu_info): New.
    (release_op_data): Call that.
    (parse_tofu_user): New.
    (parse_tofu_stats): New.
    (parse_tofu_stats_long): New.
    (_gpgme_verify_status_handler): Handle TOFU status lines.
    
    * tests/run-verify.c (print_description): New.
    (print_result): print tofu info.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/NEWS b/NEWS
index 119866e..04cfe12 100644
--- a/NEWS
+++ b/NEWS
@@ -6,8 +6,15 @@ Noteworthy changes in version 1.7.0 (unreleased) [C25/A14/R_]
  * Interface changes relative to the 1.6.0 release:
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  gpgme_pubkey_algo_string       NEW.
- gpgme_set_ctx_flag             NEW.
  GPGME_PK_EDDSA                 NEW.
+ gpgme_set_ctx_flag             NEW.
+ gpgme_signature_t              EXTENDED: New field tofu.
+ gpgme_tofu_policy_t            NEW.
+ gpgme_tofu_info_t              NEW.
+ GPGME_STATUS_KEY_CONSIDERED    NEW.
+ GPGME_STATUS_TOFU_USER         NEW.
+ GPGME_STATUS_TOFU_STATS        NEW.
+ GPGME_STATUS_TOFU_STATS_LONG   NEW.
 
 
 Noteworthy changes in version 1.6.0 (2015-08-26) [C25/A14/R0]
diff --git a/src/gpgme.h.in b/src/gpgme.h.in
index 5f7896d..335ed6b 100644
--- a/src/gpgme.h.in
+++ b/src/gpgme.h.in
@@ -371,6 +371,19 @@ typedef enum
 gpgme_validity_t;
 
 
+/* The TOFU policies. */
+typedef enum
+  {
+    GPGME_TOFU_POLICY_NONE    = 0,
+    GPGME_TOFU_POLICY_AUTO    = 1,
+    GPGME_TOFU_POLICY_GOOD    = 2,
+    GPGME_TOFU_POLICY_UNKNOWN = 3,
+    GPGME_TOFU_POLICY_BAD     = 4,
+    GPGME_TOFU_POLICY_ASK     = 5
+  }
+gpgme_tofu_policy_t;
+
+
 /* The available protocols.  */
 typedef enum
   {
@@ -533,7 +546,10 @@ typedef enum
     GPGME_STATUS_KEY_NOT_CREATED = 91,
     GPGME_STATUS_INQUIRE_MAXLEN = 92,
     GPGME_STATUS_FAILURE = 93,
-    GPGME_STATUS_KEY_CONSIDERED = 94
+    GPGME_STATUS_KEY_CONSIDERED = 94,
+    GPGME_STATUS_TOFU_USER = 95,
+    GPGME_STATUS_TOFU_STATS = 96,
+    GPGME_STATUS_TOFU_STATS_LONG = 97
   }
 gpgme_status_code_t;
 
@@ -1533,6 +1549,46 @@ typedef enum
   }
 gpgme_sigsum_t;
 
+
+struct _gpgme_tofu_info
+{
+  struct _gpgme_tofu_info *next;
+
+  /* The mail address (addr-spec from RFC5322) of the tofu binding.  */
+  char *address;
+
+  /* The fingerprint of the primary key.  */
+  char *fpr;
+
+  /* The TOFU validity:
+   *  0 := conflict
+   *  1 := key without history
+   *  2 := key with too little history
+   *  3 := key with enough history for basic trust
+   *  4 := key with a lot of history
+   */
+  unsigned int validity : 3;
+
+  /* The TOFU policy (gpgme_tofu_policy_t).  */
+  unsigned int policy : 4;
+
+  unsigned int _rfu : 25;
+
+  /* Number of signatures seen for this binding.  Capped at USHRT_MAX.  */
+  unsigned short signcount;
+  unsigned short reserved;
+
+  /* Number of seconds since the first and the most recently seen
+   * message was verified.  */
+  unsigned int firstseen;
+  unsigned int lastseen;
+
+  /* If non-NULL a human readable string summarizing the TOFU data. */
+  char *description;
+};
+typedef struct _gpgme_tofu_info *gpgme_tofu_info_t;
+
+
 struct _gpgme_signature
 {
   struct _gpgme_signature *next;
@@ -1578,6 +1634,9 @@ struct _gpgme_signature
 
   /* The mailbox from the PKA information or NULL. */
   char *pka_address;
+
+  /* If non-NULL, TOFU info for this signature are available.  */
+  gpgme_tofu_info_t tofu;
 };
 typedef struct _gpgme_signature *gpgme_signature_t;
 
diff --git a/src/status-table.c b/src/status-table.c
index e70cb8b..5850a36 100644
--- a/src/status-table.c
+++ b/src/status-table.c
@@ -124,6 +124,9 @@ static struct status_table_s status_table[] =
   { "SIG_SUBPACKET", GPGME_STATUS_SIG_SUBPACKET },
   { "SIGEXPIRED", GPGME_STATUS_SIGEXPIRED },
   { "SUCCESS", GPGME_STATUS_SUCCESS },
+  { "TOFU_STATS", GPGME_STATUS_TOFU_STATS },
+  { "TOFU_STATS_LONG", GPGME_STATUS_TOFU_STATS_LONG },
+  { "TOFU_USER", GPGME_STATUS_TOFU_USER },
   { "TRUNCATED", GPGME_STATUS_TRUNCATED },
   { "TRUST_FULLY", GPGME_STATUS_TRUST_FULLY },
   { "TRUST_MARGINAL", GPGME_STATUS_TRUST_MARGINAL },
diff --git a/src/verify.c b/src/verify.c
index 4781d99..e6c9665 100644
--- a/src/verify.c
+++ b/src/verify.c
@@ -26,6 +26,7 @@
 #include <string.h>
 #include <errno.h>
 #include <assert.h>
+#include <limits.h>
 
 #include "gpgme.h"
 #include "debug.h"
@@ -49,6 +50,22 @@ typedef struct
 
 
 static void
+release_tofu_info (gpgme_tofu_info_t t)
+{
+  while (t)
+    {
+      gpgme_tofu_info_t t2 = t->next;
+
+      free (t->address);
+      free (t->fpr);
+      free (t->description);
+      free (t);
+      t = t2;
+    }
+}
+
+
+static void
 release_op_data (void *hook)
 {
   op_data_t opd = (op_data_t) hook;
@@ -71,6 +88,7 @@ release_op_data (void *hook)
 	free (sig->fpr);
       if (sig->pka_address)
 	free (sig->pka_address);
+      release_tofu_info (sig->tofu);
       free (sig);
       sig = next;
     }
@@ -635,6 +653,169 @@ parse_trust (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
 }
 
 
+/* Parse a TOFU_USER line and put the info into SIG.  */
+static gpgme_error_t
+parse_tofu_user (gpgme_signature_t sig, char *args)
+{
+  gpg_error_t err;
+  char *tail;
+  gpgme_tofu_info_t ti, ti2;
+
+  tail = strchr (args, ' ');
+  if (!tail || tail == args)
+    return trace_gpg_error (GPG_ERR_INV_ENGINE);  /* No fingerprint.  */
+  *tail++ = 0;
+
+  ti = calloc (1, sizeof *ti);
+  if (!ti)
+    return gpg_error_from_syserror ();
+
+  ti->fpr = strdup (args);
+  if (!ti->fpr)
+    {
+      free (ti);
+      return gpg_error_from_syserror ();
+    }
+
+  args = tail;
+  tail = strchr (args, ' ');
+  if (tail == args)
+    return trace_gpg_error (GPG_ERR_INV_ENGINE);  /* No addr-spec.  */
+  if (tail)
+    *tail = 0;
+
+  err = _gpgme_decode_percent_string (args, &ti->address, 0, 0);
+  if (err)
+    {
+      free (ti);
+      return err;
+    }
+
+  /* Append to the tofu info list.  */
+  if (!sig->tofu)
+    sig->tofu = ti;
+  else
+    {
+      for (ti2 = sig->tofu; ti2->next; ti2 = ti2->next)
+        ;
+      ti2->next = ti;
+    }
+
+  return 0;
+}
+
+
+/* Parse a TOFU_STATS line and store it in the last tofu info of SIG.
+ *
+ *   TOFU_STATS <validity> <sign-count> 0 [<policy> [<tm1> <tm2>]]
+ */
+static gpgme_error_t
+parse_tofu_stats (gpgme_signature_t sig, char *args)
+{
+  gpgme_error_t err;
+  gpgme_tofu_info_t ti;
+  char *field[6];
+  int nfields;
+  unsigned long uval;
+
+  if (!sig->tofu)
+    return trace_gpg_error (GPG_ERR_INV_ENGINE); /* No TOFU_USER seen.  */
+  for (ti = sig->tofu; ti->next; ti = ti->next)
+    ;
+  if (ti->firstseen || ti->signcount || ti->validity || ti->policy)
+    return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Already seen.  */
+
+  nfields = _gpgme_split_fields (args, field, DIM (field));
+  if (nfields < 3)
+    return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Required args missing.  */
+
+  /* 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[0], &uval);
+  if (err || uval > 7)
+    return trace_gpg_error (GPG_ERR_INV_ENGINE);
+  ti->validity = uval;
+
+  /* Parse the sign-count.  */
+  err = _gpgme_strtoul_field (field[1], &uval);
+  if (err)
+    return trace_gpg_error (GPG_ERR_INV_ENGINE);
+  if (uval > USHRT_MAX)
+    uval = USHRT_MAX;
+  ti->signcount = uval;
+
+  /* We skip the 0, which is RFU.  */
+
+  if (nfields == 3)
+    return 0; /* All mandatory fields parsed.  */
+
+  /* Parse the policy.  */
+  if (!strcmp (field[3], "none"))
+    ti->policy = GPGME_TOFU_POLICY_NONE;
+  else if (!strcmp (field[3], "auto"))
+    ti->policy = GPGME_TOFU_POLICY_AUTO;
+  else if (!strcmp (field[3], "good"))
+    ti->policy = GPGME_TOFU_POLICY_GOOD;
+  else if (!strcmp (field[3], "bad"))
+    ti->policy = GPGME_TOFU_POLICY_BAD;
+  else if (!strcmp (field[3], "ask"))
+    ti->policy = GPGME_TOFU_POLICY_ASK;
+  else /* "unknown" and invalid policy strings.  */
+    ti->policy = GPGME_TOFU_POLICY_UNKNOWN;
+
+  if (nfields == 4)
+    return 0; /* No more optional fields.  */
+
+  /* Parse first and last seen (none or both are required).  */
+  if (nfields < 6)
+    return trace_gpg_error (GPG_ERR_INV_ENGINE); /* "tm2" missing.  */
+  err = _gpgme_strtoul_field (field[4], &uval);
+  if (err)
+    return trace_gpg_error (GPG_ERR_INV_ENGINE);
+  if (uval > UINT_MAX)
+    uval = UINT_MAX;
+  ti->firstseen = uval;
+  err = _gpgme_strtoul_field (field[5], &uval);
+  if (err)
+    return trace_gpg_error (GPG_ERR_INV_ENGINE);
+  if (uval > UINT_MAX)
+    uval = UINT_MAX;
+  ti->lastseen = uval;
+
+  return 0;
+}
+
+
+/* Parse a TOFU_STATS_LONG line and store it in the last tofu info of SIG.  */
+static gpgme_error_t
+parse_tofu_stats_long (gpgme_signature_t sig, char *args, int raw)
+{
+  gpgme_error_t err;
+  gpgme_tofu_info_t ti;
+  char *p;
+
+  if (!sig->tofu)
+    return trace_gpg_error (GPG_ERR_INV_ENGINE); /* No TOFU_USER seen.  */
+  for (ti = sig->tofu; ti->next; ti = ti->next)
+    ;
+  if (ti->description)
+    return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Already seen.  */
+
+  err = _gpgme_decode_percent_string (args, &ti->description, 0, 0);
+  if (err)
+    return err;
+
+  /* Remove the non-breaking spaces.  */
+  if (!raw)
+    {
+      for (p = ti->description; *p; p++)
+        if (*p == '~')
+          *p = ' ';
+    }
+  return 0;
+}
+
+
 /* Parse an error status line and if SET_STATUS is true update the
    result status as appropriate.  With SET_STATUS being false, only
    check for an error.  */
@@ -766,6 +947,21 @@ _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
       sig->pka_address = strdup (args);
       break;
 
+    case GPGME_STATUS_TOFU_USER:
+      opd->only_newsig_seen = 0;
+      return sig ? parse_tofu_user (sig, args)
+        /*    */ : trace_gpg_error (GPG_ERR_INV_ENGINE);
+
+    case GPGME_STATUS_TOFU_STATS:
+      opd->only_newsig_seen = 0;
+      return sig ? parse_tofu_stats (sig, args)
+        /*    */ : trace_gpg_error (GPG_ERR_INV_ENGINE);
+
+    case GPGME_STATUS_TOFU_STATS_LONG:
+      opd->only_newsig_seen = 0;
+      return sig ? parse_tofu_stats_long (sig, args, ctx->raw_description)
+        /*    */ : trace_gpg_error (GPG_ERR_INV_ENGINE);
+
     case GPGME_STATUS_ERROR:
       opd->only_newsig_seen = 0;
       /* Some  error stati are informational, so we don't return an
diff --git a/tests/run-verify.c b/tests/run-verify.c
index b7be320..df8cbf6 100644
--- a/tests/run-verify.c
+++ b/tests/run-verify.c
@@ -94,9 +94,23 @@ print_validity (gpgme_validity_t val)
 
 
 static void
+print_description (const char *text, int indent)
+{
+  for (; *text; text++)
+    {
+      putchar (*text);
+      if (*text == '\n')
+        printf ("%*s", indent, "");
+    }
+  putchar ('\n');
+}
+
+
+static void
 print_result (gpgme_verify_result_t result)
 {
   gpgme_signature_t sig;
+  gpgme_tofu_info_t ti;
   int count = 0;
 
   printf ("Original file name: %s\n", nonnull(result->file_name));
@@ -126,6 +140,30 @@ print_result (gpgme_verify_result_t result)
               );
       printf ("  notations .: %s\n",
               sig->notations? "yes":"no");
+      for (ti = sig->tofu; ti; ti = ti->next)
+        {
+          printf ("  tofu addr .: %s\n", ti->address);
+          if (!sig->fpr || strcmp (sig->fpr, ti->fpr))
+            printf ("    WARNING .: fpr mismatch (%s)\n", ti->fpr);
+          printf ("    validity : %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 ("    sigcount : %hu\n", ti->signcount);
+          printf ("    firstseen: %u\n", ti->firstseen);
+          printf ("    lastseen : %u\n", ti->lastseen);
+          printf ("    desc ....: ");
+          print_description (nonnull (ti->description), 15);
+        }
     }
 }
 
@@ -230,6 +268,7 @@ main (int argc, char **argv)
       gpgme_set_status_cb (ctx, status_cb, NULL);
       gpgme_set_ctx_flag (ctx, "full-status", "1");
     }
+  /* gpgme_set_ctx_flag (ctx, "raw-description", "1"); */
 
   err = gpgme_data_new_from_stream (&sig, fp_sig);
   if (err)

commit dac2c5441d418536632f014c8b0e1359580279d1
Author: Werner Koch <wk at gnupg.org>
Date:   Sat May 21 10:22:57 2016 +0200

    api: Add new context flag "raw-description".
    
    * src/context.h (struct gpgme_context): Add field raw_description.
    * src/gpgme.c (gpgme_set_ctx_flag): New flag.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/doc/gpgme.texi b/doc/gpgme.texi
index 4d7a874..8d666c3 100644
--- a/doc/gpgme.texi
+++ b/doc/gpgme.texi
@@ -2752,6 +2752,12 @@ gpgme_set_status_cb returns all status lines with the exception of
 PROGRESS lines.  With the default of "0" the status callback is only
 called in certain situations.
 
+ at item "raw-description"
+Setting the @var{value} to "1" returns human readable strings in a raw
+format.  For example the non breaking space characters ("~") will not
+be removed from the @code{description} field of the
+ at code{gpgme_tofu_info_t} object.
+
 @end table
 
 This function returns @code{0} on success.
diff --git a/src/context.h b/src/context.h
index 078f0cb..de69a7a 100644
--- a/src/context.h
+++ b/src/context.h
@@ -105,6 +105,11 @@ struct gpgme_context
    * lines.  */
   unsigned int full_status : 1;
 
+  /* The Tofu info has a human readable string which is presented to
+   * the user in a directly usable format.  By enabling this flag the
+   * unmodified string, as received form gpg, will be returned.  */
+  unsigned int raw_description : 1;
+
   /* Flags for keylist mode.  */
   gpgme_keylist_mode_t keylist_mode;
 
diff --git a/src/gpgme.c b/src/gpgme.c
index 3289be9..e0cd9b0 100644
--- a/src/gpgme.c
+++ b/src/gpgme.c
@@ -93,11 +93,20 @@ gpgme_set_global_flag (const char *name, const char *value)
 gpgme_error_t
 gpgme_set_ctx_flag (gpgme_ctx_t ctx, const char *name, const char *value)
 {
+  int abool;
+
   if (!ctx || !name || !value)
     return gpg_error (GPG_ERR_INV_VALUE);
-  else if (!strcmp (name, "full-status"))
+
+  abool = *value? !!atoi (value) : 0;
+
+  if (!strcmp (name, "full-status"))
+    {
+      ctx->full_status = abool;
+    }
+  else if (!strcmp (name, "raw-description"))
     {
-      ctx->full_status = *value? !!atoi (value) : 0;
+      ctx->raw_description = abool;
     }
   else
     return gpg_error (GPG_ERR_UNKNOWN_NAME);

commit a92946a8cacc44f655249d84b316deae59e62671
Author: Werner Koch <wk at gnupg.org>
Date:   Sat May 21 10:21:06 2016 +0200

    core: New functions to help parsing of status lines.
    
    * src/conversion.c (_gpgme_split_fields): New.
    (_gpgme_strtoul_field): New.
    --
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/src/conversion.c b/src/conversion.c
index 0992225..c2b27a1 100644
--- a/src/conversion.c
+++ b/src/conversion.c
@@ -317,6 +317,53 @@ _gpgme_encode_percent_string (const char *src, char **destp, size_t len)
 }
 
 
+/* Split a string into space delimited fields and remove leading and
+ * trailing spaces from each field.  A pointer to the each field is
+ * stored in ARRAY.  Stop splitting at ARRAYSIZE fields.  The function
+ * modifies STRING.  The number of parsed fields is returned.
+ */
+int
+_gpgme_split_fields (char *string, char **array, int arraysize)
+{
+  int n = 0;
+  char *p, *pend;
+
+  for (p = string; *p == ' '; p++)
+    ;
+  do
+    {
+      if (n == arraysize)
+        break;
+      array[n++] = p;
+      pend = strchr (p, ' ');
+      if (!pend)
+        break;
+      *pend++ = 0;
+      for (p = pend; *p == ' '; p++)
+        ;
+    }
+  while (*p);
+
+  return n;
+}
+
+/* Convert the field STRING into an unsigned long value.  Check for
+ * trailing garbage.  */
+gpgme_error_t
+_gpgme_strtoul_field (const char *string, unsigned long *result)
+{
+  char *endp;
+
+  gpg_err_set_errno (0);
+  *result = strtoul (string, &endp, 0);
+  if (errno)
+    return gpg_error_from_syserror ();
+  if (endp == string || *endp)
+    return gpg_error (GPG_ERR_INV_VALUE);
+  return 0;
+}
+
+
 #ifdef HAVE_W32_SYSTEM
 static time_t
 _gpgme_timegm (struct tm *tm)
diff --git a/src/util.h b/src/util.h
index 365f1d8..9c62f57 100644
--- a/src/util.h
+++ b/src/util.h
@@ -124,6 +124,15 @@ gpgme_error_t _gpgme_decode_percent_string (const char *src, char **destp,
 gpgme_error_t _gpgme_encode_percent_string (const char *src, char **destp,
 					    size_t len);
 
+/* Split a string into space delimited fields and remove leading and
+ * trailing spaces from each field.  A pointer to the each field is
+ * stored in ARRAY.  Stop splitting at ARRAYSIZE fields.  The function
+ * modifies STRING.  The number of parsed fields is returned.  */
+int _gpgme_split_fields (char *string, char **array, int arraysize);
+
+/* Convert the field STRING into an unsigned long value.  Check for
+ * trailing garbage.  */
+gpgme_error_t _gpgme_strtoul_field (const char *string, unsigned long *result);
 
 /* Parse the string TIMESTAMP into a time_t.  The string may either be
    seconds since Epoch or in the ISO 8601 format like

-----------------------------------------------------------------------

Summary of changes:
 NEWS               |   9 ++-
 doc/gpgme.texi     |   6 ++
 src/context.h      |   5 ++
 src/conversion.c   |  47 +++++++++++++
 src/gpgme.c        |  13 +++-
 src/gpgme.h.in     |  61 ++++++++++++++++-
 src/status-table.c |   3 +
 src/util.h         |   9 +++
 src/verify.c       | 196 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 tests/run-verify.c |  39 +++++++++++
 10 files changed, 384 insertions(+), 4 deletions(-)


hooks/post-receive
-- 
GnuPG Made Easy
http://git.gnupg.org




More information about the Gnupg-commits mailing list