diff --git a/NEWS b/NEWS index f4f75aa5..84e484cd 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,7 @@ Noteworthy changes in version CVS-HEAD * Interface changes relative to the 0.3.6 release: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +GPGME_ATTR_ERRTOK NEW ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Noteworthy changes in version 0.3.7 (2002-06-04) diff --git a/doc/ChangeLog b/doc/ChangeLog index 58b37994..19a292c0 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,7 @@ +2002-06-10 Werner Koch + + * gpgme.texi (Verify): Document attribute GPGME_ATTR_ERRTOK. + 2002-06-04 Marcus Brinkmann * gpgme.texi (Multi Threading): Document new autodetection. @@ -183,3 +187,13 @@ * fdl.texi: Likewise. * Makefile.am (info_TEXINFOS): New variable. (gpgme_TEXINFOS): Likewise. + + Copyright 2002 g10 Code GmbH + + This file is free software; as a special exception the author gives + unlimited permission to copy and/or distribute it, with or without + modifications, as long as this notice is preserved. + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, to the extent permitted by law; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. diff --git a/doc/gpgme.texi b/doc/gpgme.texi index 6f64e454..9e6ee615 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -2217,16 +2217,17 @@ fingerprint of the key which signed the plaintext, or @code{NULL} if no verification could be performed. @end deftypefun -@deftypefun {const char *} gpgme_get_sig_string_attr (@w{GpgmeCtx @var{ctx}}, @w{int @var{idx}}, @w{GpgmeAttr @var{waht}}, @w{int @var{reserved}}) +@deftypefun {const char *} gpgme_get_sig_string_attr (@w{GpgmeCtx @var{ctx}}, @w{int @var{idx}}, @w{GpgmeAttr @var{what}}, @w{int @var{reserved}}) This function is similar to @code{gpgme_get_sig_status} but may be used to retrieve more detailed information. @var{ctx} should be the context used for the last signature verification, @var{idx} is used to enumerate over all signatures starting with @code{0} and @var{reserved} should be @code{0} for now. -The only attribute @var{what} currently supported is +The attributes @var{what} currently supports are @code{GPGME_ATTR_FPR} to return the fingerprint of the key used to -create the signature. +create the signature and @code{GPGME_ERRTOK} to return a token +with a more detailed error description. @end deftypefun @deftypefun {const char *} gpgme_get_sig_ulong_attr (@w{GpgmeCtx @var{ctx}}, @w{int @var{idx}}, @w{GpgmeAttr @var{waht}}, @w{int @var{reserved}}) diff --git a/gpgme/ChangeLog b/gpgme/ChangeLog index 1c65289a..20f74bf0 100644 --- a/gpgme/ChangeLog +++ b/gpgme/ChangeLog @@ -1,3 +1,21 @@ +2002-06-11 Werner Koch + + * gpgme.h: Add GPGME_ATTR_SIG_SUMMARY and the GPGME_SIGSUM_ + constants. + * verify.c (calc_sig_summary): New. + (gpgme_get_sig_ulong_attr): And use it here. + +2002-06-10 Werner Koch + + * rungpg.h: Add new status codes TRUNCATED and ERROR. + * verify.c (is_token, copy_token): New. + (_gpgme_verify_status_handler): Use copy_token, handle the new + ERROR status and store the errorcode used withgpgsm and trust + status codes. + * gpgme.h: New attribute ERRTOK. + * key.c (gpgme_key_get_string_attr): Add dummy case for it. + (gpgme_get_sig_string_attr): Use it here to return the last error. + 2002-06-10 Marcus Brinkmann * engine-gpgsm.c (_gpgme_gpgsm_start): Move the code that sets the diff --git a/gpgme/gpgme.h b/gpgme/gpgme.h index 16484318..cc781cdc 100644 --- a/gpgme/gpgme.h +++ b/gpgme/gpgme.h @@ -137,6 +137,23 @@ typedef enum } GpgmeSigStat; +/* Flags used with the GPGME_ATTR_SIG_SUMMARY. */ +enum + { + GPGME_SIGSUM_VALID = 0x0001, /* The signature is fully valid */ + GPGME_SIGSUM_GREEN = 0x0002, /* The signature is good. */ + GPGME_SIGSUM_RED = 0x0004, /* The signature is bad. */ + GPGME_SIGSUM_KEY_REVOKED = 0x0010, /* One key has been revoked. */ + GPGME_SIGSUM_KEY_EXPIRED = 0x0020, /* One key has expired. */ + GPGME_SIGSUM_SIG_EXPIRED = 0x0040, /* The signature has expired. */ + GPGME_SIGSUM_KEY_MISSING = 0x0080, /* Can't verify: key missing. */ + GPGME_SIGSUM_CRL_MISSING = 0x0100, /* CRL not available. */ + GPGME_SIGSUM_CRL_TOO_OLD = 0x0200, /* Available CRL is too old. */ + GPGME_SIGSUM_BAD_POLICY = 0x0400, /* A policy was not met. */ + GPGME_SIGSUM_SYS_ERROR = 0x0800 /* A system error occured. */ + }; + + /* The available signature modes. */ typedef enum { @@ -177,7 +194,9 @@ typedef enum GPGME_ATTR_SERIAL = 26, GPGME_ATTR_ISSUER = 27, GPGME_ATTR_CHAINID = 28, - GPGME_ATTR_SIG_STATUS = 29 + GPGME_ATTR_SIG_STATUS = 29, + GPGME_ATTR_ERRTOK = 30, + GPGME_ATTR_SIG_SUMMARY = 31 } GpgmeAttr; diff --git a/gpgme/key.c b/gpgme/key.c index 94973da3..879be144 100644 --- a/gpgme/key.c +++ b/gpgme/key.c @@ -990,6 +990,7 @@ gpgme_key_get_string_attr (GpgmeKey key, GpgmeAttr what, val = key->chain_id; break; case GPGME_ATTR_SIG_STATUS: + case GPGME_ATTR_ERRTOK: /* Not of any use here. */ break; } diff --git a/gpgme/key.h b/gpgme/key.h index 39a13161..e827217d 100644 --- a/gpgme/key.h +++ b/gpgme/key.h @@ -79,8 +79,3 @@ GpgmeError _gpgme_key_append_name ( GpgmeKey key, const char *s ); #endif /* KEY_H */ - - - - - diff --git a/gpgme/rungpg.h b/gpgme/rungpg.h index 20fffe6f..a798caf3 100644 --- a/gpgme/rungpg.h +++ b/gpgme/rungpg.h @@ -102,7 +102,9 @@ typedef enum { STATUS_ALREADY_SIGNED , STATUS_SIGEXPIRED , STATUS_EXPSIG , - STATUS_EXPKEYSIG + STATUS_EXPKEYSIG , + STATUS_TRUNCATED , + STATUS_ERROR , } GpgStatusCode; typedef void (*GpgStatusHandler)( GpgmeCtx, GpgStatusCode code, char *args ); diff --git a/gpgme/verify.c b/gpgme/verify.c index dc71dbd6..6afa1ebc 100644 --- a/gpgme/verify.c +++ b/gpgme/verify.c @@ -44,6 +44,7 @@ struct verify_result_s ulong timestamp; /* Signature creation time. */ ulong exptimestamp; /* signature exipration time or 0 */ GpgmeValidity validity; + char trust_errtok[31]; /* error token send with the trust status */ }; @@ -59,6 +60,44 @@ _gpgme_release_verify_result (VerifyResult result) } } +/* Check whether STRING starts with TOKEN and return true in this + case. This is case insensitive. If NEXT is not NULL return the + number of bytes to be added to STRING to get to the next token; a + returned value of 0 indicates end of line. */ +static int +is_token (const char *string, const char *token, size_t *next) +{ + size_t n = 0; + + for (;*string && *token && *string == *token; string++, token++, n++) + ; + if (*token || (*string != ' ' && !*string)) + return 0; + if (next) + { + for (; *string == ' '; string++, n++) + ; + *next = n; + } + return 1; +} + +static size_t +copy_token (const char *string, char *buffer, size_t length) +{ + const char *s = string; + char *p = buffer; + size_t i; + + for (i = 1; i < length && *s && *s != ' ' ; i++) + *p++ = *s++; + *p = 0; + /* conmtinue scanning in case the copy was truncated */ + while (*s && *s != ' ') + s++; + return s - string; +} + /* FIXME: Check that we are adding this to the correct signature. */ static void @@ -147,6 +186,7 @@ void _gpgme_verify_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) { char *p; + size_t n; int i; if (ctx->error) @@ -184,11 +224,8 @@ _gpgme_verify_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) 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; + i = copy_token (args, ctx->result.verify->fpr, + DIM(ctx->result.verify->fpr)); /* Skip the formatted date. */ while (args[i] && args[i] == ' ') i++; @@ -203,16 +240,13 @@ _gpgme_verify_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) 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; + copy_token (args, ctx->result.verify->fpr, + DIM(ctx->result.verify->fpr)); break; case STATUS_ERRSIG: /* The return code is the 6th argument, if it is 9, the problem - is a missing key. */ + is a missing key. Note that this is not emitted by gpgsm */ for (p = args, i = 0; p && *p && i < 5; i++) { p = strchr (p, ' '); @@ -225,11 +259,8 @@ _gpgme_verify_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) else ctx->result.verify->status = GPGME_SIG_STAT_ERROR; /* 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; + copy_token (args, ctx->result.verify->fpr, + DIM(ctx->result.verify->fpr)); break; case STATUS_NOTATION_NAME: @@ -240,13 +271,19 @@ _gpgme_verify_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) case STATUS_TRUST_UNDEFINED: ctx->result.verify->validity = GPGME_VALIDITY_UNKNOWN; + copy_token (args, ctx->result.verify->trust_errtok, + DIM(ctx->result.verify->trust_errtok)); break; case STATUS_TRUST_NEVER: ctx->result.verify->validity = GPGME_VALIDITY_NEVER; + copy_token (args, ctx->result.verify->trust_errtok, + DIM(ctx->result.verify->trust_errtok)); break; case STATUS_TRUST_MARGINAL: if (ctx->result.verify->status == GPGME_SIG_STAT_GOOD) ctx->result.verify->validity = GPGME_VALIDITY_MARGINAL; + copy_token (args, ctx->result.verify->trust_errtok, + DIM(ctx->result.verify->trust_errtok)); break; case STATUS_TRUST_FULLY: case STATUS_TRUST_ULTIMATE: @@ -257,6 +294,20 @@ _gpgme_verify_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) case STATUS_END_STREAM: break; + case STATUS_ERROR: + /* Generic error, we need this for gpgsm (and maybe for gpg in future) + to get error descriptions. */ + if (is_token (args, "verify.findkey", &n) && n) + { + args += n; + if (is_token (args, "No_Public_Key", NULL)) + ctx->result.verify->status = GPGME_SIG_STAT_NOKEY; + else + ctx->result.verify->status = GPGME_SIG_STAT_ERROR; + + } + break; + case STATUS_EOF: finish_sig (ctx,1); @@ -451,6 +502,55 @@ gpgme_get_sig_status (GpgmeCtx c, int idx, return result->fpr; } + +/* Build a summary vector from RESULT. */ +static unsigned long +calc_sig_summary (VerifyResult result) +{ + unsigned long sum = 0; + + if (result->validity == GPGME_VALIDITY_FULL + || result->validity == GPGME_VALIDITY_ULTIMATE) + { + if (result->status == GPGME_SIG_STAT_GOOD + || result->status == GPGME_SIG_STAT_GOOD_EXP + || result->status == GPGME_SIG_STAT_GOOD_EXPKEY) + sum |= GPGME_SIGSUM_GREEN; + } + else if (result->validity == GPGME_VALIDITY_NEVER) + { + if (result->status == GPGME_SIG_STAT_GOOD + || result->status == GPGME_SIG_STAT_GOOD_EXP + || result->status == GPGME_SIG_STAT_GOOD_EXPKEY) + sum |= GPGME_SIGSUM_RED; + } + else if (result->status == GPGME_SIG_STAT_BAD) + sum |= GPGME_SIGSUM_RED; + + /* fixme: handle the case when key and message are expired. */ + if (result->status == GPGME_SIG_STAT_GOOD_EXP) + sum |= GPGME_SIGSUM_SIG_EXPIRED; + else if (result->status == GPGME_SIG_STAT_GOOD_EXPKEY) + sum |= GPGME_SIGSUM_KEY_EXPIRED; + else if (result->status == GPGME_SIG_STAT_NOKEY) + sum |= GPGME_SIGSUM_KEY_MISSING; + else if (result->status == GPGME_SIG_STAT_ERROR) + sum |= GPGME_SIGSUM_SYS_ERROR; + + /* FIXME: Set GPGME_SIGSUM_KEY_REVOKED. */ + /* FIXME: Set GPGME_SIGSUM_CRL_MISSING. */ + /* FIXME: Set GPGME_SIGSUM_CRL_TOO_OLD. */ + /* FIXME: Set GPGME_SIGSUM_BAD_POLICY. */ + + /* That the valid flag when the signature is unquestionable + valid. */ + if ((sum & GPGME_SIGSUM_GREEN) && !(sum & ~GPGME_SIGSUM_GREEN)) + sum |= GPGME_SIGSUM_VALID; + + return sum; +} + + const char * gpgme_get_sig_string_attr (GpgmeCtx c, int idx, GpgmeAttr what, int reserved) { @@ -471,6 +571,8 @@ gpgme_get_sig_string_attr (GpgmeCtx c, int idx, GpgmeAttr what, int reserved) { case GPGME_ATTR_FPR: return result->fpr; + case GPGME_ATTR_ERRTOK: + return result->trust_errtok; default: break; } @@ -502,6 +604,8 @@ gpgme_get_sig_ulong_attr (GpgmeCtx c, int idx, GpgmeAttr what, int reserved) return (unsigned long)result->validity; case GPGME_ATTR_SIG_STATUS: return (unsigned long)result->status; + case GPGME_ATTR_SIG_SUMMARY: + return calc_sig_summary (result); default: break; } diff --git a/tests/ChangeLog b/tests/ChangeLog index e1538b33..5ab20b21 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,7 @@ +2002-06-10 Werner Koch + + * gpgsm/t-verify.c (print_sig_stat): Print the error token. + 2002-06-04 Werner Koch * gpgsm/t-encrypt.c (main): Add a simple option parser and allow diff --git a/tests/gpgsm/t-verify.c b/tests/gpgsm/t-verify.c index fcd1c678..9ce6678e 100644 --- a/tests/gpgsm/t-verify.c +++ b/tests/gpgsm/t-verify.c @@ -118,8 +118,9 @@ print_sig_stat ( GpgmeCtx ctx, GpgmeSigStat status ) idx, (unsigned long)created, gpgme_get_sig_ulong_attr (ctx, idx, GPGME_ATTR_EXPIRE, 0), status_string(status) ); - printf ("sig %d: fpr/keyid: `%s' validity: %s\n", + printf ("sig %d: fpr/keyid: `%s' exterr: `%s' validity: %s\n", idx, s, + gpgme_get_sig_string_attr (ctx, idx, GPGME_ATTR_ERRTOK, 0), validity_string (gpgme_get_sig_ulong_attr (ctx, idx, GPGME_ATTR_VALIDITY, 0)) ); if ( !gpgme_get_sig_key (ctx, idx, &key) ) {