From be0ca741fd12897337408d1d7a7d8f5f18e1fac9 Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Wed, 16 Nov 2011 16:06:07 -0600 Subject: Finish rename from prior commit --- libtdenetwork/libgpgme-copy/gpgme/verify.c | 992 +++++++++++++++++++++++++++++ 1 file changed, 992 insertions(+) create mode 100644 libtdenetwork/libgpgme-copy/gpgme/verify.c (limited to 'libtdenetwork/libgpgme-copy/gpgme/verify.c') diff --git a/libtdenetwork/libgpgme-copy/gpgme/verify.c b/libtdenetwork/libgpgme-copy/gpgme/verify.c new file mode 100644 index 000000000..4000a61c7 --- /dev/null +++ b/libtdenetwork/libgpgme-copy/gpgme/verify.c @@ -0,0 +1,992 @@ +/* verify.c - Signature verification. + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 2004, 2005 g10 Code GmbH + + This file is part of GPGME. + + GPGME is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + GPGME is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#if HAVE_CONFIG_H +#include +#endif +#include +#include +#include +#include + +#include "gpgme.h" +#include "util.h" +#include "context.h" +#include "ops.h" + + +typedef struct +{ + struct _gpgme_op_verify_result result; + + gpgme_signature_t current_sig; + int did_prepare_new_sig; + int only_newsig_seen; + int plaintext_seen; +} *op_data_t; + + +static void +release_op_data (void *hook) +{ + op_data_t opd = (op_data_t) hook; + gpgme_signature_t sig = opd->result.signatures; + + while (sig) + { + gpgme_signature_t next = sig->next; + gpgme_sig_notation_t notation = sig->notations; + + while (notation) + { + gpgme_sig_notation_t next_nota = notation->next; + + _gpgme_sig_notation_free (notation); + notation = next_nota; + } + + if (sig->fpr) + free (sig->fpr); + if (sig->pka_address) + free (sig->pka_address); + free (sig); + sig = next; + } + + if (opd->result.file_name) + free (opd->result.file_name); +} + + +gpgme_verify_result_t +gpgme_op_verify_result (gpgme_ctx_t ctx) +{ + void *hook; + op_data_t opd; + gpgme_error_t err; + + err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook, -1, NULL); + opd = hook; + if (err || !opd) + return NULL; + + return &opd->result; +} + + +/* Build a summary vector from RESULT. */ +static void +calc_sig_summary (gpgme_signature_t sig) +{ + unsigned long sum = 0; + + /* Calculate the red/green flag. */ + if (sig->validity == GPGME_VALIDITY_FULL + || sig->validity == GPGME_VALIDITY_ULTIMATE) + { + if (gpg_err_code (sig->status) == GPG_ERR_NO_ERROR + || gpg_err_code (sig->status) == GPG_ERR_SIG_EXPIRED + || gpg_err_code (sig->status) == GPG_ERR_KEY_EXPIRED) + sum |= GPGME_SIGSUM_GREEN; + } + else if (sig->validity == GPGME_VALIDITY_NEVER) + { + if (gpg_err_code (sig->status) == GPG_ERR_NO_ERROR + || gpg_err_code (sig->status) == GPG_ERR_SIG_EXPIRED + || gpg_err_code (sig->status) == GPG_ERR_KEY_EXPIRED) + sum |= GPGME_SIGSUM_RED; + } + else if (gpg_err_code (sig->status) == GPG_ERR_BAD_SIGNATURE) + sum |= GPGME_SIGSUM_RED; + + + /* FIXME: handle the case when key and message are expired. */ + switch (gpg_err_code (sig->status)) + { + case GPG_ERR_SIG_EXPIRED: + sum |= GPGME_SIGSUM_SIG_EXPIRED; + break; + + case GPG_ERR_KEY_EXPIRED: + sum |= GPGME_SIGSUM_KEY_EXPIRED; + break; + + case GPG_ERR_NO_PUBKEY: + sum |= GPGME_SIGSUM_KEY_MISSING; + break; + + case GPG_ERR_BAD_SIGNATURE: + case GPG_ERR_NO_ERROR: + break; + + default: + sum |= GPGME_SIGSUM_SYS_ERROR; + break; + } + + /* Now look at the certain reason codes. */ + switch (gpg_err_code (sig->validity_reason)) + { + case GPG_ERR_CRL_TOO_OLD: + if (sig->validity == GPGME_VALIDITY_UNKNOWN) + sum |= GPGME_SIGSUM_CRL_TOO_OLD; + break; + + case GPG_ERR_CERT_REVOKED: + sum |= GPGME_SIGSUM_KEY_REVOKED; + break; + + default: + break; + } + + /* Check other flags. */ + if (sig->wrong_key_usage) + sum |= GPGME_SIGSUM_BAD_POLICY; + + /* Set the valid flag when the signature is unquestionable + valid. */ + if ((sum & GPGME_SIGSUM_GREEN) && !(sum & ~GPGME_SIGSUM_GREEN)) + sum |= GPGME_SIGSUM_VALID; + + sig->summary = sum; +} + + +static gpgme_error_t +prepare_new_sig (op_data_t opd) +{ + gpgme_signature_t sig; + + if (opd->only_newsig_seen && opd->current_sig) + { + /* We have only seen the NEWSIG status and nothing else - we + better skip this signature therefore and reuse it for the + next possible signature. */ + sig = opd->current_sig; + memset (sig, 0, sizeof *sig); + assert (opd->result.signatures == sig); + } + else + { + sig = calloc (1, sizeof (*sig)); + if (!sig) + return gpg_error_from_errno (errno); + if (!opd->result.signatures) + opd->result.signatures = sig; + if (opd->current_sig) + opd->current_sig->next = sig; + opd->current_sig = sig; + } + opd->did_prepare_new_sig = 1; + opd->only_newsig_seen = 0; + return 0; +} + +static gpgme_error_t +parse_new_sig (op_data_t opd, gpgme_status_code_t code, char *args) +{ + gpgme_signature_t sig; + char *end = strchr (args, ' '); + char *tail; + + if (end) + { + *end = '\0'; + end++; + } + + if (!opd->did_prepare_new_sig) + { + gpg_error_t err; + + err = prepare_new_sig (opd); + if (err) + return err; + } + assert (opd->did_prepare_new_sig); + opd->did_prepare_new_sig = 0; + + assert (opd->current_sig); + sig = opd->current_sig; + + /* FIXME: We should set the source of the state. */ + switch (code) + { + case GPGME_STATUS_GOODSIG: + sig->status = gpg_error (GPG_ERR_NO_ERROR); + break; + + case GPGME_STATUS_EXPSIG: + sig->status = gpg_error (GPG_ERR_SIG_EXPIRED); + break; + + case GPGME_STATUS_EXPKEYSIG: + sig->status = gpg_error (GPG_ERR_KEY_EXPIRED); + break; + + case GPGME_STATUS_BADSIG: + sig->status = gpg_error (GPG_ERR_BAD_SIGNATURE); + break; + + case GPGME_STATUS_REVKEYSIG: + sig->status = gpg_error (GPG_ERR_CERT_REVOKED); + break; + + case GPGME_STATUS_ERRSIG: + /* Parse the pubkey algo. */ + if (!end) + goto parse_err_sig_fail; + errno = 0; + sig->pubkey_algo = strtol (end, &tail, 0); + if (errno || end == tail || *tail != ' ') + goto parse_err_sig_fail; + end = tail; + while (*end == ' ') + end++; + + /* Parse the hash algo. */ + if (!*end) + goto parse_err_sig_fail; + errno = 0; + sig->hash_algo = strtol (end, &tail, 0); + if (errno || end == tail || *tail != ' ') + goto parse_err_sig_fail; + end = tail; + while (*end == ' ') + end++; + + /* Skip the sig class. */ + end = strchr (end, ' '); + if (!end) + goto parse_err_sig_fail; + while (*end == ' ') + end++; + + /* Parse the timestamp. */ + sig->timestamp = _gpgme_parse_timestamp (end, &tail); + if (sig->timestamp == -1 || end == tail || (*tail && *tail != ' ')) + return gpg_error (GPG_ERR_INV_ENGINE); + end = tail; + while (*end == ' ') + end++; + + /* Parse the return code. */ + if (end[0] && (!end[1] || end[1] == ' ')) + { + switch (end[0]) + { + case '4': + sig->status = gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); + break; + + case '9': + sig->status = gpg_error (GPG_ERR_NO_PUBKEY); + break; + + default: + sig->status = gpg_error (GPG_ERR_GENERAL); + } + } + else + goto parse_err_sig_fail; + + goto parse_err_sig_ok; + + parse_err_sig_fail: + sig->status = gpg_error (GPG_ERR_GENERAL); + parse_err_sig_ok: + break; + + default: + return gpg_error (GPG_ERR_GENERAL); + } + + if (*args) + { + sig->fpr = strdup (args); + if (!sig->fpr) + return gpg_error_from_errno (errno); + } + return 0; +} + + +static gpgme_error_t +parse_valid_sig (gpgme_signature_t sig, char *args) +{ + char *end = strchr (args, ' '); + if (end) + { + *end = '\0'; + end++; + } + + if (!*args) + /* We require at least the fingerprint. */ + return gpg_error (GPG_ERR_GENERAL); + + if (sig->fpr) + free (sig->fpr); + sig->fpr = strdup (args); + if (!sig->fpr) + return gpg_error_from_errno (errno); + + /* Skip the creation date. */ + end = strchr (end, ' '); + if (end) + { + char *tail; + + sig->timestamp = _gpgme_parse_timestamp (end, &tail); + if (sig->timestamp == -1 || end == tail || (*tail && *tail != ' ')) + return gpg_error (GPG_ERR_INV_ENGINE); + end = tail; + + sig->exp_timestamp = _gpgme_parse_timestamp (end, &tail); + if (sig->exp_timestamp == -1 || end == tail || (*tail && *tail != ' ')) + return gpg_error (GPG_ERR_INV_ENGINE); + end = tail; + + while (*end == ' ') + end++; + /* Skip the signature version. */ + end = strchr (end, ' '); + if (end) + { + while (*end == ' ') + end++; + + /* Skip the reserved field. */ + end = strchr (end, ' '); + if (end) + { + /* Parse the pubkey algo. */ + errno = 0; + sig->pubkey_algo = strtol (end, &tail, 0); + if (errno || end == tail || *tail != ' ') + return gpg_error (GPG_ERR_INV_ENGINE); + end = tail; + + while (*end == ' ') + end++; + + if (*end) + { + /* Parse the hash algo. */ + + errno = 0; + sig->hash_algo = strtol (end, &tail, 0); + if (errno || end == tail || *tail != ' ') + return gpg_error (GPG_ERR_INV_ENGINE); + end = tail; + } + } + } + } + return 0; +} + + +static gpgme_error_t +parse_notation (gpgme_signature_t sig, gpgme_status_code_t code, char *args) +{ + gpgme_error_t err; + gpgme_sig_notation_t *lastp = &sig->notations; + gpgme_sig_notation_t notation = sig->notations; + char *end = strchr (args, ' '); + + if (end) + *end = '\0'; + + if (code == GPGME_STATUS_NOTATION_NAME || code == GPGME_STATUS_POLICY_URL) + { + /* FIXME: We could keep a pointer to the last notation in the list. */ + while (notation && notation->value) + { + lastp = ¬ation->next; + notation = notation->next; + } + + if (notation) + /* There is another notation name without data for the + previous one. The crypto backend misbehaves. */ + return gpg_error (GPG_ERR_INV_ENGINE); + + err = _gpgme_sig_notation_create (¬ation, NULL, 0, NULL, 0, 0); + if (err) + return err; + + if (code == GPGME_STATUS_NOTATION_NAME) + { + err = _gpgme_decode_percent_string (args, ¬ation->name, 0, 0); + if (err) + { + _gpgme_sig_notation_free (notation); + return err; + } + + notation->name_len = strlen (notation->name); + + /* FIXME: For now we fake the human-readable flag. The + critical flag can not be reported as it is not + provided. */ + notation->flags = GPGME_SIG_NOTATION_HUMAN_READABLE; + notation->human_readable = 1; + } + else + { + /* This is a policy URL. */ + + err = _gpgme_decode_percent_string (args, ¬ation->value, 0, 0); + if (err) + { + _gpgme_sig_notation_free (notation); + return err; + } + + notation->value_len = strlen (notation->value); + } + *lastp = notation; + } + else if (code == GPGME_STATUS_NOTATION_DATA) + { + int len = strlen (args) + 1; + char *dest; + + /* FIXME: We could keep a pointer to the last notation in the list. */ + while (notation && notation->next) + { + lastp = ¬ation->next; + notation = notation->next; + } + + if (!notation || !notation->name) + /* There is notation data without a previous notation + name. The crypto backend misbehaves. */ + return gpg_error (GPG_ERR_INV_ENGINE); + + if (!notation->value) + { + dest = notation->value = malloc (len); + if (!dest) + return gpg_error_from_errno (errno); + } + else + { + int cur_len = strlen (notation->value); + dest = realloc (notation->value, len + strlen (notation->value)); + if (!dest) + return gpg_error_from_errno (errno); + notation->value = dest; + dest += cur_len; + } + + err = _gpgme_decode_percent_string (args, &dest, len, 0); + if (err) + return err; + + notation->value_len += strlen (dest); + } + else + return gpg_error (GPG_ERR_INV_ENGINE); + return 0; +} + + +static gpgme_error_t +parse_trust (gpgme_signature_t sig, gpgme_status_code_t code, char *args) +{ + char *end = strchr (args, ' '); + + if (end) + *end = '\0'; + + switch (code) + { + case GPGME_STATUS_TRUST_UNDEFINED: + default: + sig->validity = GPGME_VALIDITY_UNKNOWN; + break; + + case GPGME_STATUS_TRUST_NEVER: + sig->validity = GPGME_VALIDITY_NEVER; + break; + + case GPGME_STATUS_TRUST_MARGINAL: + sig->validity = GPGME_VALIDITY_MARGINAL; + break; + + case GPGME_STATUS_TRUST_FULLY: + case GPGME_STATUS_TRUST_ULTIMATE: + sig->validity = GPGME_VALIDITY_FULL; + break; + } + + if (*args) + sig->validity_reason = _gpgme_map_gnupg_error (args); + else + sig->validity_reason = 0; + + 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. */ +static gpgme_error_t +parse_error (gpgme_signature_t sig, char *args, int set_status) +{ + gpgme_error_t err; + char *where = strchr (args, ' '); + char *which; + + if (where) + { + *where = '\0'; + which = where + 1; + + where = strchr (which, ' '); + if (where) + *where = '\0'; + + where = args; + } + else + return gpg_error (GPG_ERR_INV_ENGINE); + + err = _gpgme_map_gnupg_error (which); + + if (!strcmp (where, "proc_pkt.plaintext") + && gpg_err_code (err) == GPG_ERR_BAD_DATA) + { + /* This indicates a double plaintext. The only solid way to + handle this is by failing the oepration. */ + return gpg_error (GPG_ERR_BAD_DATA); + } + else if (!set_status) + ; + else if (!strcmp (where, "verify.findkey")) + sig->status = err; + else if (!strcmp (where, "verify.keyusage") + && gpg_err_code (err) == GPG_ERR_WRONG_KEY_USAGE) + sig->wrong_key_usage = 1; + + return 0; +} + + +gpgme_error_t +_gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args) +{ + gpgme_ctx_t ctx = (gpgme_ctx_t) priv; + gpgme_error_t err; + void *hook; + op_data_t opd; + gpgme_signature_t sig; + char *end; + + err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook, -1, NULL); + opd = hook; + if (err) + return err; + + sig = opd->current_sig; + + switch (code) + { + case GPGME_STATUS_NEWSIG: + if (sig) + calc_sig_summary (sig); + err = prepare_new_sig (opd); + opd->only_newsig_seen = 1; + return err; + + case GPGME_STATUS_GOODSIG: + case GPGME_STATUS_EXPSIG: + case GPGME_STATUS_EXPKEYSIG: + case GPGME_STATUS_BADSIG: + case GPGME_STATUS_ERRSIG: + case GPGME_STATUS_REVKEYSIG: + if (sig && !opd->did_prepare_new_sig) + calc_sig_summary (sig); + opd->only_newsig_seen = 0; + return parse_new_sig (opd, code, args); + + case GPGME_STATUS_VALIDSIG: + opd->only_newsig_seen = 0; + return sig ? parse_valid_sig (sig, args) + : gpg_error (GPG_ERR_INV_ENGINE); + + case GPGME_STATUS_NODATA: + opd->only_newsig_seen = 0; + if (!sig) + return gpg_error (GPG_ERR_NO_DATA); + sig->status = gpg_error (GPG_ERR_NO_DATA); + break; + + case GPGME_STATUS_UNEXPECTED: + opd->only_newsig_seen = 0; + if (!sig) + return gpg_error (GPG_ERR_GENERAL); + sig->status = gpg_error (GPG_ERR_NO_DATA); + break; + + case GPGME_STATUS_NOTATION_NAME: + case GPGME_STATUS_NOTATION_DATA: + case GPGME_STATUS_POLICY_URL: + opd->only_newsig_seen = 0; + return sig ? parse_notation (sig, code, args) + : gpg_error (GPG_ERR_INV_ENGINE); + + case GPGME_STATUS_TRUST_UNDEFINED: + case GPGME_STATUS_TRUST_NEVER: + case GPGME_STATUS_TRUST_MARGINAL: + case GPGME_STATUS_TRUST_FULLY: + case GPGME_STATUS_TRUST_ULTIMATE: + opd->only_newsig_seen = 0; + return sig ? parse_trust (sig, code, args) + : gpg_error (GPG_ERR_INV_ENGINE); + + case GPGME_STATUS_PKA_TRUST_BAD: + case GPGME_STATUS_PKA_TRUST_GOOD: + opd->only_newsig_seen = 0; + /* Check that we only get one of these status codes per + signature; if not the crypto backend misbehaves. */ + if (!sig || sig->pka_trust || sig->pka_address) + return gpg_error (GPG_ERR_INV_ENGINE); + sig->pka_trust = code == GPGME_STATUS_PKA_TRUST_GOOD? 2 : 1; + end = strchr (args, ' '); + if (end) + *end = 0; + sig->pka_address = strdup (args); + break; + + case GPGME_STATUS_ERROR: + opd->only_newsig_seen = 0; + /* Some error stati are informational, so we don't return an + error code if we are not ready to process this status. */ + return parse_error (sig, args, !!sig ); + + case GPGME_STATUS_EOF: + if (sig && !opd->did_prepare_new_sig) + calc_sig_summary (sig); + if (opd->only_newsig_seen && sig) + { + gpgme_signature_t sig2; + /* The last signature has no valid information - remove it + from the list. */ + assert (!sig->next); + if (sig == opd->result.signatures) + opd->result.signatures = NULL; + else + { + for (sig2 = opd->result.signatures; sig2; sig2 = sig2->next) + if (sig2->next == sig) + { + sig2->next = NULL; + break; + } + } + /* Note that there is no need to release the members of SIG + because we won't be here if they have been set. */ + free (sig); + opd->current_sig = NULL; + } + opd->only_newsig_seen = 0; + break; + + case GPGME_STATUS_PLAINTEXT: + if (++opd->plaintext_seen > 1) + return gpg_error (GPG_ERR_BAD_DATA); + err = _gpgme_parse_plaintext (args, &opd->result.file_name); + if (err) + return err; + + default: + break; + } + return 0; +} + + +static gpgme_error_t +verify_status_handler (void *priv, gpgme_status_code_t code, char *args) +{ + gpgme_error_t err; + + err = _gpgme_progress_status_handler (priv, code, args); + if (!err) + err = _gpgme_verify_status_handler (priv, code, args); + return err; +} + + +gpgme_error_t +_gpgme_op_verify_init_result (gpgme_ctx_t ctx) +{ + void *hook; + op_data_t opd; + + return _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook, + sizeof (*opd), release_op_data); +} + + +static gpgme_error_t +verify_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t sig, + gpgme_data_t signed_text, gpgme_data_t plaintext) +{ + gpgme_error_t err; + + err = _gpgme_op_reset (ctx, synchronous); + if (err) + return err; + + err = _gpgme_op_verify_init_result (ctx); + if (err) + return err; + + _gpgme_engine_set_status_handler (ctx->engine, verify_status_handler, ctx); + + if (!sig) + return gpg_error (GPG_ERR_NO_DATA); + if (!signed_text && !plaintext) + return gpg_error (GPG_ERR_INV_VALUE); + + return _gpgme_engine_op_verify (ctx->engine, sig, signed_text, plaintext); +} + + +/* Decrypt ciphertext CIPHER and make a signature verification within + CTX and store the resulting plaintext in PLAIN. */ +gpgme_error_t +gpgme_op_verify_start (gpgme_ctx_t ctx, gpgme_data_t sig, + gpgme_data_t signed_text, gpgme_data_t plaintext) +{ + return verify_start (ctx, 0, sig, signed_text, plaintext); +} + + +/* Decrypt ciphertext CIPHER and make a signature verification within + CTX and store the resulting plaintext in PLAIN. */ +gpgme_error_t +gpgme_op_verify (gpgme_ctx_t ctx, gpgme_data_t sig, gpgme_data_t signed_text, + gpgme_data_t plaintext) +{ + gpgme_error_t err; + + err = verify_start (ctx, 1, sig, signed_text, plaintext); + if (!err) + err = _gpgme_wait_one (ctx); + return err; +} + + +/* Compatibility interfaces. */ + +/* Get the key used to create signature IDX in CTX and return it in + R_KEY. */ +gpgme_error_t +gpgme_get_sig_key (gpgme_ctx_t ctx, int idx, gpgme_key_t *r_key) +{ + gpgme_verify_result_t result; + gpgme_signature_t sig; + + result = gpgme_op_verify_result (ctx); + sig = result->signatures; + + while (sig && idx) + { + sig = sig->next; + idx--; + } + if (!sig || idx) + return gpg_error (GPG_ERR_EOF); + + return gpgme_get_key (ctx, sig->fpr, r_key, 0); +} + + +/* Retrieve the signature status of signature IDX in CTX after a + successful verify operation in R_STAT (if non-null). The creation + time stamp of the signature is returned in R_CREATED (if non-null). + The function returns a string containing the fingerprint. */ +const char * +gpgme_get_sig_status (gpgme_ctx_t ctx, int idx, + _gpgme_sig_stat_t *r_stat, time_t *r_created) +{ + gpgme_verify_result_t result; + gpgme_signature_t sig; + + result = gpgme_op_verify_result (ctx); + sig = result->signatures; + + while (sig && idx) + { + sig = sig->next; + idx--; + } + if (!sig || idx) + return NULL; + + if (r_stat) + { + switch (gpg_err_code (sig->status)) + { + case GPG_ERR_NO_ERROR: + *r_stat = GPGME_SIG_STAT_GOOD; + break; + + case GPG_ERR_BAD_SIGNATURE: + *r_stat = GPGME_SIG_STAT_BAD; + break; + + case GPG_ERR_NO_PUBKEY: + *r_stat = GPGME_SIG_STAT_NOKEY; + break; + + case GPG_ERR_NO_DATA: + *r_stat = GPGME_SIG_STAT_NOSIG; + break; + + case GPG_ERR_SIG_EXPIRED: + *r_stat = GPGME_SIG_STAT_GOOD_EXP; + break; + + case GPG_ERR_KEY_EXPIRED: + *r_stat = GPGME_SIG_STAT_GOOD_EXPKEY; + break; + + default: + *r_stat = GPGME_SIG_STAT_ERROR; + break; + } + } + if (r_created) + *r_created = sig->timestamp; + return sig->fpr; +} + + +/* Retrieve certain attributes of a signature. IDX is the index + number of the signature after a successful verify operation. WHAT + is an attribute where GPGME_ATTR_EXPIRE is probably the most useful + one. WHATIDX is to be passed as 0 for most attributes . */ +unsigned long +gpgme_get_sig_ulong_attr (gpgme_ctx_t ctx, int idx, + _gpgme_attr_t what, int whatidx) +{ + gpgme_verify_result_t result; + gpgme_signature_t sig; + + result = gpgme_op_verify_result (ctx); + sig = result->signatures; + + while (sig && idx) + { + sig = sig->next; + idx--; + } + if (!sig || idx) + return 0; + + switch (what) + { + case GPGME_ATTR_CREATED: + return sig->timestamp; + + case GPGME_ATTR_EXPIRE: + return sig->exp_timestamp; + + case GPGME_ATTR_VALIDITY: + return (unsigned long) sig->validity; + + case GPGME_ATTR_SIG_STATUS: + switch (gpg_err_code (sig->status)) + { + case GPG_ERR_NO_ERROR: + return GPGME_SIG_STAT_GOOD; + + case GPG_ERR_BAD_SIGNATURE: + return GPGME_SIG_STAT_BAD; + + case GPG_ERR_NO_PUBKEY: + return GPGME_SIG_STAT_NOKEY; + + case GPG_ERR_NO_DATA: + return GPGME_SIG_STAT_NOSIG; + + case GPG_ERR_SIG_EXPIRED: + return GPGME_SIG_STAT_GOOD_EXP; + + case GPG_ERR_KEY_EXPIRED: + return GPGME_SIG_STAT_GOOD_EXPKEY; + + default: + return GPGME_SIG_STAT_ERROR; + } + + case GPGME_ATTR_SIG_SUMMARY: + return sig->summary; + + default: + break; + } + return 0; +} + + +const char * +gpgme_get_sig_string_attr (gpgme_ctx_t ctx, int idx, + _gpgme_attr_t what, int whatidx) +{ + gpgme_verify_result_t result; + gpgme_signature_t sig; + + result = gpgme_op_verify_result (ctx); + sig = result->signatures; + + while (sig && idx) + { + sig = sig->next; + idx--; + } + if (!sig || idx) + return NULL; + + switch (what) + { + case GPGME_ATTR_FPR: + return sig->fpr; + + case GPGME_ATTR_ERRTOK: + if (whatidx == 1) + return sig->wrong_key_usage ? "Wrong_Key_Usage" : ""; + else + return ""; + default: + break; + } + + return NULL; +} -- cgit v1.2.1