aboutsummaryrefslogtreecommitdiffstats
path: root/src/verify.c
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2016-05-21 08:29:49 +0000
committerWerner Koch <[email protected]>2016-05-21 08:32:51 +0000
commit10df06ee8f9192309bf124872438f7c32457e1c6 (patch)
treefa06a7511fea47cf784f9ac0e003bf04ecb0c27c /src/verify.c
parentapi: Add new context flag "raw-description". (diff)
downloadgpgme-10df06ee8f9192309bf124872438f7c32457e1c6.tar.gz
gpgme-10df06ee8f9192309bf124872438f7c32457e1c6.zip
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 <[email protected]>
Diffstat (limited to 'src/verify.c')
-rw-r--r--src/verify.c196
1 files changed, 196 insertions, 0 deletions
diff --git a/src/verify.c b/src/verify.c
index 4781d995..e6c9665f 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