diff options
Diffstat (limited to '')
| -rw-r--r-- | TODO | 3 | ||||
| -rw-r--r-- | gpgme/ChangeLog | 11 | ||||
| -rw-r--r-- | gpgme/debug.c | 1 | ||||
| -rw-r--r-- | gpgme/gpgme.h | 10 | ||||
| -rw-r--r-- | gpgme/keylist.c | 1 | ||||
| -rw-r--r-- | gpgme/verify.c | 189 | ||||
| -rw-r--r-- | tests/t-verify.c | 51 | 
7 files changed, 245 insertions, 21 deletions
| @@ -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 ); | 
