aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--TODO3
-rw-r--r--gpgme/ChangeLog11
-rw-r--r--gpgme/debug.c1
-rw-r--r--gpgme/gpgme.h10
-rw-r--r--gpgme/keylist.c1
-rw-r--r--gpgme/verify.c189
-rw-r--r--tests/t-verify.c51
7 files changed, 245 insertions, 21 deletions
diff --git a/TODO b/TODO
index c6f65057..1ef478da 100644
--- a/TODO
+++ b/TODO
@@ -5,4 +5,7 @@
* Allow to use GTK's main loop instead of the select stuff in
wait.c
+* a op_keylist_start should cancel a pending keylisy operation on the
+ same context
+
* need to close a lot of handles in w32-io.c
diff --git a/gpgme/ChangeLog b/gpgme/ChangeLog
index 6b63ca21..ea4ac7eb 100644
--- a/gpgme/ChangeLog
+++ b/gpgme/ChangeLog
@@ -1,3 +1,14 @@
+2001-02-12 Werner Koch <[email protected]>
+
+ Enhanced the signature verification, so that it can how handle
+ more than one signature and is able to return more information on
+ the signatures.
+ * verify.c (gpgme_get_sig_key): New.
+ (gpgme_get_sig_status): New.
+
+ * gpgme.h: Add stdio.h.
+ (GpgmeSigStat): New status DIFF.
+
2001-02-01 Werner Koch <[email protected]>
* w32-io.c (set_synchronize): Add EVENT_MODIFY_STATE. Add Debug
diff --git a/gpgme/debug.c b/gpgme/debug.c
index e700405b..19de2a7d 100644
--- a/gpgme/debug.c
+++ b/gpgme/debug.c
@@ -23,6 +23,7 @@
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
+#include <unistd.h>
#include <assert.h>
#include "util.h"
diff --git a/gpgme/gpgme.h b/gpgme/gpgme.h
index 73744922..cecb912c 100644
--- a/gpgme/gpgme.h
+++ b/gpgme/gpgme.h
@@ -21,6 +21,7 @@
#ifndef GPGME_H
#define GPGME_H
+#include <stdio.h> /* for FILE * */
#ifdef _MSC_VER
typedef long off_t;
#else
@@ -103,7 +104,8 @@ typedef enum {
GPGME_SIG_STAT_BAD = 2,
GPGME_SIG_STAT_NOKEY = 3,
GPGME_SIG_STAT_NOSIG = 4,
- GPGME_SIG_STAT_ERROR = 5
+ GPGME_SIG_STAT_ERROR = 5,
+ GPGME_SIG_STAT_DIFF = 6
} GpgmeSigStat;
typedef enum {
@@ -165,6 +167,12 @@ void gpgme_signers_clear (GpgmeCtx c);
GpgmeError gpgme_signers_add (GpgmeCtx c, const GpgmeKey key);
GpgmeKey gpgme_signers_enum (const GpgmeCtx c, int seq);
+const char *gpgme_get_sig_status (GpgmeCtx c, int idx,
+ GpgmeSigStat *r_stat, time_t *r_created );
+GpgmeError gpgme_get_sig_key (GpgmeCtx c, int idx, GpgmeKey *r_key);
+
+
+
/* Functions to handle recipients */
GpgmeError gpgme_recipients_new (GpgmeRecipients *r_rset);
diff --git a/gpgme/keylist.c b/gpgme/keylist.c
index 9fea4257..8b360e00 100644
--- a/gpgme/keylist.c
+++ b/gpgme/keylist.c
@@ -359,7 +359,6 @@ gpgme_op_keylist_start ( GpgmeCtx c, const char *pattern, int secret_only )
_gpgme_release_result (c);
c->out_of_core = 0;
-#warning This context still keeps a gpg Zombie in some cases.
if ( c->gpg ) {
_gpgme_gpg_release ( c->gpg );
c->gpg = NULL;
diff --git a/gpgme/verify.c b/gpgme/verify.c
index cc203959..7a1af985 100644
--- a/gpgme/verify.c
+++ b/gpgme/verify.c
@@ -29,21 +29,28 @@
#include "ops.h"
struct verify_result_s {
+ struct verify_result_s *next;
GpgmeSigStat status;
GpgmeData notation; /* we store an XML fragment here */
-
+ int collecting; /* private to finish_sig() */
int notation_in_data; /* private to add_notation() */
+ char fpr[41]; /* fingerprint of a good signature or keyid of a bad one*/
+ ulong timestamp; /* signature creation time */
};
void
_gpgme_release_verify_result ( VerifyResult res )
{
- gpgme_data_release ( res->notation );
- xfree (res);
+ while (res) {
+ VerifyResult r2 = res->next;
+ gpgme_data_release ( res->notation );
+ xfree (res);
+ res = r2;
+ }
}
-
+/* fixme: check that we are adding this to the correct signature */
static void
add_notation ( GpgmeCtx ctx, GpgStatusCode code, const char *data )
{
@@ -86,9 +93,42 @@ add_notation ( GpgmeCtx ctx, GpgStatusCode code, const char *data )
}
}
+
+/*
+ * finish a pending signature info collection and prepare for a new
+ * signature info collection
+ */
+static void
+finish_sig (GpgmeCtx ctx, int stop)
+{
+ if (stop)
+ return; /* nothing to do */
+
+ if (ctx->result.verify->collecting) {
+ VerifyResult res2;
+
+ ctx->result.verify->collecting = 0;
+ /* create a new result structure */
+ res2 = xtrycalloc ( 1, sizeof *res2 );
+ if ( !res2 ) {
+ ctx->out_of_core = 1;
+ return;
+ }
+
+ res2->next = ctx->result.verify;
+ ctx->result.verify = res2;
+ }
+
+ ctx->result.verify->collecting = 1;
+}
+
+
static void
verify_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args )
{
+ char *p;
+ int i;
+
if ( ctx->out_of_core )
return;
if ( ctx->result_type == RESULT_TYPE_NONE ) {
@@ -102,20 +142,54 @@ verify_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args )
}
assert ( ctx->result_type == RESULT_TYPE_VERIFY );
- /* FIXME: For now we handle only one signature */
- /* FIXME: Collect useful information
- and return them as XML */
+ if (code == STATUS_GOODSIG
+ || code == STATUS_BADSIG || code == STATUS_ERRSIG) {
+ finish_sig (ctx,0);
+ if ( ctx->out_of_core )
+ return;
+ }
+
switch (code) {
case STATUS_GOODSIG:
+ /* We just look at VALIDSIG */
+ break;
+
+ case STATUS_VALIDSIG:
ctx->result.verify->status = GPGME_SIG_STAT_GOOD;
+ p = ctx->result.verify->fpr;
+ for (i=0; i < DIM(ctx->result.verify->fpr)
+ && args[i] && args[i] != ' ' ; i++ )
+ *p++ = args[i];
+ *p = 0;
+ /* skip the formatted date */
+ while ( args[i] && args[i] == ' ')
+ i++;
+ while ( args[i] && args[i] != ' ')
+ i++;
+ /* and get the timestamp */
+ ctx->result.verify->timestamp = strtoul (args+i, NULL, 10);
break;
+
case STATUS_BADSIG:
ctx->result.verify->status = GPGME_SIG_STAT_BAD;
+ /* store the keyID in the fpr field */
+ p = ctx->result.verify->fpr;
+ for (i=0; i < DIM(ctx->result.verify->fpr)
+ && args[i] && args[i] != ' ' ; i++ )
+ *p++ = args[i];
+ *p = 0;
break;
+
case STATUS_ERRSIG:
ctx->result.verify->status = GPGME_SIG_STAT_ERROR;
/* FIXME: distinguish between a regular error and a missing key.
* this is encoded in the args. */
+ /* store the keyID in the fpr field */
+ p = ctx->result.verify->fpr;
+ for (i=0; i < DIM(ctx->result.verify->fpr)
+ && args[i] && args[i] != ' ' ; i++ )
+ *p++ = args[i];
+ *p = 0;
break;
case STATUS_NOTATION_NAME:
@@ -127,6 +201,10 @@ verify_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args )
case STATUS_END_STREAM:
break;
+ case STATUS_EOF:
+ finish_sig(ctx,1);
+ break;
+
default:
/* ignore all other codes */
break;
@@ -205,6 +283,21 @@ gpgme_op_verify_start ( GpgmeCtx c, GpgmeData sig, GpgmeData text )
}
+/*
+ * Figure out a common status value for all signatures
+ */
+static GpgmeSigStat
+intersect_stati ( VerifyResult res )
+{
+ GpgmeSigStat status = res->status;
+
+ for (res=res->next; res; res = res->next) {
+ if (status != res->status )
+ return GPGME_SIG_STAT_DIFF;
+ }
+ return status;
+}
+
/**
* gpgme_op_verify:
* @c: the context
@@ -223,7 +316,8 @@ gpgme_op_verify_start ( GpgmeCtx c, GpgmeData sig, GpgmeData text )
* missing key
* GPGME_SIG_STAT_NOSIG: This is not a signature
* GPGME_SIG_STAT_ERROR: Due to some other error the check could not be done.
- * FIXME: What do we return if only some o the signatures ae valid?
+ * GPGME_SIG_STAT_DIFF: There is more than 1 signature and they have not
+ * the same status.
*
* Return value: 0 on success or an errorcode if something not related to
* the signature itself did go wrong.
@@ -250,6 +344,7 @@ gpgme_op_verify ( GpgmeCtx c, GpgmeData sig, GpgmeData text,
rc = mk_error (Out_Of_Core);
else {
assert ( c->result.verify );
+ /* fixme: Put all notation data into one XML fragment */
if ( c->result.verify->notation ) {
GpgmeData dh = c->result.verify->notation;
@@ -261,7 +356,7 @@ gpgme_op_verify ( GpgmeCtx c, GpgmeData sig, GpgmeData text,
c->notation = dh;
c->result.verify->notation = NULL;
}
- *r_stat = c->result.verify->status;
+ *r_stat = intersect_stati (c->result.verify);
}
c->pending = 0;
}
@@ -269,6 +364,82 @@ gpgme_op_verify ( GpgmeCtx c, GpgmeData sig, GpgmeData text,
}
+/**
+ * gpgme_get_sig_status:
+ * @c: Context
+ * @idx: Index of the signature starting at 0
+ * @r_stat: Returns the status
+ * @r_created: Returns the creation timestamp
+ *
+ * Return information about an already verified signatures.
+ *
+ * Return value: The fingerprint or NULL in case of an problem or
+ * when there are no more signatures.
+ **/
+const char *
+gpgme_get_sig_status (GpgmeCtx c, int idx,
+ GpgmeSigStat *r_stat, time_t *r_created )
+{
+ VerifyResult res;
+
+ if (!c || c->pending || c->result_type != RESULT_TYPE_VERIFY )
+ return NULL; /* No results yet or verification error */
+
+ for (res = c->result.verify; res && idx>0 ; res = res->next, idx--)
+ ;
+ if (!res)
+ return NULL; /* No more signatures */
+
+ if (r_stat)
+ *r_stat = res->status;
+ if (r_created)
+ *r_created = res->timestamp;
+ return res->fpr;
+}
+
+
+/**
+ * gpgme_get_sig_key:
+ * @c: context
+ * @idx: Index of the signature starting at 0
+ * @r_key: Returns the key object
+ *
+ * Return a key object which was used to check the signature.
+ *
+ * Return value: An Errorcode or 0 for success. GPG<ME_EOF is returned to
+ * indicate that there are no more signatures.
+ **/
+GpgmeError
+gpgme_get_sig_key (GpgmeCtx c, int idx, GpgmeKey *r_key)
+{
+ VerifyResult res;
+ GpgmeCtx listctx;
+ GpgmeError err;
+
+ if (!c || !r_key)
+ return mk_error (Invalid_Value);
+ if (c->pending || c->result_type != RESULT_TYPE_VERIFY )
+ return mk_error (Busy);
+
+ for (res = c->result.verify; res && idx>0 ; res = res->next, idx--)
+ ;
+ if (!res)
+ return mk_error (EOF);
+
+ if (strlen(res->fpr) < 16) /* we have at least an key ID */
+ return mk_error (Invalid_Key);
+
+ /* Fixme: This can me optimized keeping
+ * an internal context used for such key listings */
+ if ( (err=gpgme_new (&listctx)) )
+ return err;
+ if ( !(err=gpgme_op_keylist_start (listctx, res->fpr, 0 )) )
+ err=gpgme_op_keylist_next ( listctx, r_key );
+ gpgme_release (listctx);
+
+ return err;
+}
+
diff --git a/tests/t-verify.c b/tests/t-verify.c
index 2b91a99a..22ff1589 100644
--- a/tests/t-verify.c
+++ b/tests/t-verify.c
@@ -67,28 +67,59 @@ static const char test_sig1[] =
exit (1); } \
} while(0)
-static void
-print_sig_stat ( GpgmeSigStat status )
+
+static const char *
+status_string (GpgmeSigStat status)
{
+ const char *s = "?";
+
switch ( status ) {
case GPGME_SIG_STAT_NONE:
- fputs ("Verification Status: None\n", stdout);
+ s = "None";
break;
case GPGME_SIG_STAT_NOSIG:
- fputs ("Verification Status: No Signature\n", stdout);
+ s = "No Signature";
break;
case GPGME_SIG_STAT_GOOD:
- fputs ("Verification Status: Good\n", stdout);
+ s = "Good";
break;
case GPGME_SIG_STAT_BAD:
- fputs ("Verification Status: Bad\n", stdout);
+ s = "Bad";
break;
case GPGME_SIG_STAT_NOKEY:
- fputs ("Verification Status: No Key\n", stdout);
+ s = "No Key";
break;
case GPGME_SIG_STAT_ERROR:
- fputs ("Verification Status: Error\n", stdout);
+ s = "Error";
break;
+ case GPGME_SIG_STAT_DIFF:
+ s = "More than one signature";
+ break;
+ }
+ return s;
+}
+
+
+static void
+print_sig_stat ( GpgmeCtx ctx, GpgmeSigStat status )
+{
+ const char *s;
+ time_t created;
+ int idx;
+ GpgmeKey key;
+
+ printf ("Verification Status: %s\n", status_string (status));
+
+ for(idx=0; (s=gpgme_get_sig_status (ctx, idx, &status, &created)); idx++ ) {
+ printf ("sig %d: created: %lu status: %s\n", idx, (ulong)created,
+ status_string(status) );
+ printf ("sig %d: fpr/keyid=`%s'\n", idx, s );
+ if ( !gpgme_get_sig_key (ctx, idx, &key) ) {
+ char *p = gpgme_key_get_as_xml ( key );
+ printf ("sig %d: key object:\n%s\n", idx, p );
+ free (p);
+ gpgme_key_release (key);
+ }
}
}
@@ -118,7 +149,7 @@ main (int argc, char **argv )
puts ("checking a valid message:\n");
err = gpgme_op_verify (ctx, sig, text, &status );
- print_sig_stat ( status );
+ print_sig_stat ( ctx, status );
fail_if_err (err);
if ( (nota=gpgme_get_notation (ctx)) )
@@ -131,7 +162,7 @@ main (int argc, char **argv )
fail_if_err (err);
gpgme_data_rewind ( sig );
err = gpgme_op_verify (ctx, sig, text, &status );
- print_sig_stat ( status );
+ print_sig_stat ( ctx, status );
fail_if_err (err);
if ( (nota=gpgme_get_notation (ctx)) )
printf ("---Begin Notation---\n%s---End Notation---\n", nota );