Blame src/verify.c

Packit Service 672cf4
/* verify.c - Signature verification.
Packit Service 6c01f9
   Copyright (C) 2000 Werner Koch (dd9jn)
Packit Service 6c01f9
   Copyright (C) 2001, 2002, 2003, 2004, 2005 g10 Code GmbH
Packit Service 6c01f9
Packit Service 6c01f9
   This file is part of GPGME.
Packit Service 6c01f9
Packit Service 6c01f9
   GPGME is free software; you can redistribute it and/or modify it
Packit Service 6c01f9
   under the terms of the GNU Lesser General Public License as
Packit Service 6c01f9
   published by the Free Software Foundation; either version 2.1 of
Packit Service 6c01f9
   the License, or (at your option) any later version.
Packit Service 6c01f9
Packit Service 6c01f9
   GPGME is distributed in the hope that it will be useful, but
Packit Service 6c01f9
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 6c01f9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 6c01f9
   Lesser General Public License for more details.
Packit Service 6c01f9
Packit Service 6c01f9
   You should have received a copy of the GNU Lesser General Public
Packit Service 6c01f9
   License along with this program; if not, write to the Free Software
Packit Service 6c01f9
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
Packit Service 6c01f9
   02111-1307, USA.  */
Packit Service 672cf4
Packit Service 672cf4
#if HAVE_CONFIG_H
Packit Service 672cf4
#include <config.h>
Packit Service 672cf4
#endif
Packit Service 672cf4
#include <stdlib.h>
Packit Service 672cf4
#include <string.h>
Packit Service 672cf4
#include <errno.h>
Packit Service 672cf4
#include <assert.h>
Packit Service 672cf4
#include <limits.h>
Packit Service 672cf4
Packit Service 672cf4
#include "gpgme.h"
Packit Service 672cf4
#include "debug.h"
Packit Service 672cf4
#include "util.h"
Packit Service 672cf4
#include "context.h"
Packit Service 672cf4
#include "ops.h"
Packit Service 672cf4
Packit Service 672cf4

Packit Service 672cf4
typedef struct
Packit Service 672cf4
{
Packit Service 672cf4
  struct _gpgme_op_verify_result result;
Packit Service 672cf4
Packit Service 672cf4
  /* The error code from a FAILURE status line or 0.  */
Packit Service 672cf4
  gpg_error_t failure_code;
Packit Service 672cf4
Packit Service 672cf4
  gpgme_signature_t current_sig;
Packit Service 672cf4
  int did_prepare_new_sig;
Packit Service 672cf4
  int only_newsig_seen;
Packit Service 672cf4
  int plaintext_seen;
Packit Service 672cf4
  int conflict_user_seen;
Packit Service 672cf4
} *op_data_t;
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static void
Packit Service 672cf4
release_op_data (void *hook)
Packit Service 672cf4
{
Packit Service 672cf4
  op_data_t opd = (op_data_t) hook;
Packit Service 672cf4
  gpgme_signature_t sig = opd->result.signatures;
Packit Service 672cf4
Packit Service 672cf4
  while (sig)
Packit Service 672cf4
    {
Packit Service 672cf4
      gpgme_signature_t next = sig->next;
Packit Service 672cf4
      gpgme_sig_notation_t notation = sig->notations;
Packit Service 672cf4
Packit Service 672cf4
      while (notation)
Packit Service 672cf4
	{
Packit Service 672cf4
	  gpgme_sig_notation_t next_nota = notation->next;
Packit Service 672cf4
Packit Service 672cf4
	  _gpgme_sig_notation_free (notation);
Packit Service 672cf4
	  notation = next_nota;
Packit Service 672cf4
	}
Packit Service 672cf4
Packit Service 672cf4
      if (sig->fpr)
Packit Service 672cf4
	free (sig->fpr);
Packit Service 672cf4
      if (sig->pka_address)
Packit Service 672cf4
	free (sig->pka_address);
Packit Service 672cf4
      if (sig->key)
Packit Service 672cf4
        gpgme_key_unref (sig->key);
Packit Service 672cf4
      free (sig);
Packit Service 672cf4
      sig = next;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (opd->result.file_name)
Packit Service 672cf4
    free (opd->result.file_name);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
gpgme_verify_result_t
Packit Service 672cf4
gpgme_op_verify_result (gpgme_ctx_t ctx)
Packit Service 672cf4
{
Packit Service 672cf4
  void *hook;
Packit Service 672cf4
  op_data_t opd;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  gpgme_signature_t sig;
Packit Service 672cf4
Packit Service 6c01f9
  TRACE_BEG (DEBUG_CTX, "gpgme_op_verify_result", ctx);
Packit Service 672cf4
  err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook, -1, NULL);
Packit Service 672cf4
  opd = hook;
Packit Service 672cf4
  if (err || !opd)
Packit Service 672cf4
    {
Packit Service 6c01f9
      TRACE_SUC0 ("result=(null)");
Packit Service 672cf4
      return NULL;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  /* It is possible that we saw a new signature only followed by an
Packit Service 672cf4
     ERROR line for that.  In particular a missing X.509 key triggers
Packit Service 672cf4
     this.  In this case it is surprising that the summary field has
Packit Service 672cf4
     not been updated.  We fix it here by explicitly looking for this
Packit Service 672cf4
     case.  The real fix would be to have GPGME emit ERRSIG.  */
Packit Service 672cf4
  for (sig = opd->result.signatures; sig; sig = sig->next)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (!sig->summary)
Packit Service 672cf4
        {
Packit Service 672cf4
          switch (gpg_err_code (sig->status))
Packit Service 672cf4
            {
Packit Service 672cf4
            case GPG_ERR_KEY_EXPIRED:
Packit Service 672cf4
              sig->summary |= GPGME_SIGSUM_KEY_EXPIRED;
Packit Service 672cf4
              break;
Packit Service 672cf4
Packit Service 672cf4
            case GPG_ERR_NO_PUBKEY:
Packit Service 672cf4
              sig->summary |= GPGME_SIGSUM_KEY_MISSING;
Packit Service 672cf4
              break;
Packit Service 672cf4
Packit Service 672cf4
            default:
Packit Service 672cf4
              break;
Packit Service 672cf4
            }
Packit Service 672cf4
        }
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  /* Now for some tracing stuff. */
Packit Service 672cf4
  if (_gpgme_debug_trace ())
Packit Service 672cf4
    {
Packit Service 672cf4
      int i;
Packit Service 672cf4
Packit Service 672cf4
      for (sig = opd->result.signatures, i = 0; sig; sig = sig->next, i++)
Packit Service 672cf4
	{
Packit Service 6c01f9
	  TRACE_LOG4 ("sig[%i] = fpr %s, summary 0x%x, status %s",
Packit Service 672cf4
		      i, sig->fpr, sig->summary, gpg_strerror (sig->status));
Packit Service 6c01f9
	  TRACE_LOG6 ("sig[%i] = timestamps 0x%x/0x%x flags:%s%s%s",
Packit Service 672cf4
		      i, sig->timestamp, sig->exp_timestamp,
Packit Service 672cf4
		      sig->wrong_key_usage ? "wrong key usage" : "",
Packit Service 672cf4
		      sig->pka_trust == 1 ? "pka bad"
Packit Service 672cf4
		      : (sig->pka_trust == 2 ? "pka_okay" : "pka RFU"),
Packit Service 672cf4
		      sig->chain_model ? "chain model" : "");
Packit Service 6c01f9
	  TRACE_LOG5 ("sig[%i] = validity 0x%x (%s), algos %s/%s",
Packit Service 672cf4
		      i, sig->validity, gpg_strerror (sig->validity_reason),
Packit Service 672cf4
		      gpgme_pubkey_algo_name (sig->pubkey_algo),
Packit Service 672cf4
		      gpgme_hash_algo_name (sig->hash_algo));
Packit Service 672cf4
	  if (sig->pka_address)
Packit Service 672cf4
	    {
Packit Service 6c01f9
	      TRACE_LOG2 ("sig[%i] = PKA address %s", i, sig->pka_address);
Packit Service 672cf4
	    }
Packit Service 672cf4
	  if (sig->notations)
Packit Service 672cf4
	    {
Packit Service 6c01f9
	      TRACE_LOG1 ("sig[%i] = has notations (not shown)", i);
Packit Service 672cf4
	    }
Packit Service 672cf4
	}
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 6c01f9
  TRACE_SUC1 ("result=%p", &opd->result);
Packit Service 672cf4
  return &opd->result;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4

Packit Service 672cf4
/* Build a summary vector from RESULT. */
Packit Service 672cf4
static void
Packit Service 672cf4
calc_sig_summary (gpgme_signature_t sig)
Packit Service 672cf4
{
Packit Service 672cf4
  unsigned long sum = 0;
Packit Service 672cf4
Packit Service 672cf4
  /* Calculate the red/green flag.  */
Packit Service 672cf4
  if (sig->validity == GPGME_VALIDITY_FULL
Packit Service 672cf4
      || sig->validity == GPGME_VALIDITY_ULTIMATE)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (gpg_err_code (sig->status) == GPG_ERR_NO_ERROR
Packit Service 672cf4
	  || gpg_err_code (sig->status) == GPG_ERR_SIG_EXPIRED
Packit Service 672cf4
	  || gpg_err_code (sig->status) == GPG_ERR_KEY_EXPIRED)
Packit Service 672cf4
	sum |= GPGME_SIGSUM_GREEN;
Packit Service 672cf4
    }
Packit Service 672cf4
  else if (sig->validity == GPGME_VALIDITY_NEVER)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (gpg_err_code (sig->status) == GPG_ERR_NO_ERROR
Packit Service 672cf4
	  || gpg_err_code (sig->status) == GPG_ERR_SIG_EXPIRED
Packit Service 672cf4
	  || gpg_err_code (sig->status) == GPG_ERR_KEY_EXPIRED)
Packit Service 672cf4
	sum |= GPGME_SIGSUM_RED;
Packit Service 672cf4
    }
Packit Service 672cf4
  else if (gpg_err_code (sig->status) == GPG_ERR_BAD_SIGNATURE)
Packit Service 672cf4
    sum |= GPGME_SIGSUM_RED;
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
  /* FIXME: handle the case when key and message are expired. */
Packit Service 672cf4
  switch (gpg_err_code (sig->status))
Packit Service 672cf4
    {
Packit Service 672cf4
    case GPG_ERR_SIG_EXPIRED:
Packit Service 672cf4
      sum |= GPGME_SIGSUM_SIG_EXPIRED;
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case GPG_ERR_KEY_EXPIRED:
Packit Service 672cf4
      sum |= GPGME_SIGSUM_KEY_EXPIRED;
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case GPG_ERR_NO_PUBKEY:
Packit Service 672cf4
      sum |= GPGME_SIGSUM_KEY_MISSING;
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case GPG_ERR_CERT_REVOKED:
Packit Service 672cf4
      sum |= GPGME_SIGSUM_KEY_REVOKED;
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case GPG_ERR_BAD_SIGNATURE:
Packit Service 672cf4
    case GPG_ERR_NO_ERROR:
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    default:
Packit Service 672cf4
      sum |= GPGME_SIGSUM_SYS_ERROR;
Packit Service 672cf4
      break;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  /* Now look at the certain reason codes.  */
Packit Service 672cf4
  switch (gpg_err_code (sig->validity_reason))
Packit Service 672cf4
    {
Packit Service 672cf4
    case GPG_ERR_CRL_TOO_OLD:
Packit Service 672cf4
      if (sig->validity == GPGME_VALIDITY_UNKNOWN)
Packit Service 672cf4
        sum |= GPGME_SIGSUM_CRL_TOO_OLD;
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case GPG_ERR_CERT_REVOKED:
Packit Service 672cf4
      /* Note that this is a second way to set this flag.  It may also
Packit Service 672cf4
         have been set due to a sig->status of STATUS_REVKEYSIG from
Packit Service 672cf4
         parse_new_sig.  */
Packit Service 672cf4
      sum |= GPGME_SIGSUM_KEY_REVOKED;
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    default:
Packit Service 672cf4
      break;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  /* Check other flags. */
Packit Service 672cf4
  if (sig->wrong_key_usage)
Packit Service 672cf4
    sum |= GPGME_SIGSUM_BAD_POLICY;
Packit Service 672cf4
Packit Service 672cf4
  /* Set the valid flag when the signature is unquestionable
Packit Service 672cf4
     valid.  (The test is identical to if(sum == GPGME_SIGSUM_GREEN)). */
Packit Service 672cf4
  if ((sum & GPGME_SIGSUM_GREEN) && !(sum & ~GPGME_SIGSUM_GREEN))
Packit Service 672cf4
    sum |= GPGME_SIGSUM_VALID;
Packit Service 672cf4
Packit Service 672cf4
  sig->summary = sum;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
prepare_new_sig (op_data_t opd)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_signature_t sig;
Packit Service 672cf4
Packit Service 672cf4
  if (opd->only_newsig_seen && opd->current_sig)
Packit Service 672cf4
    {
Packit Service 672cf4
      /* We have only seen the NEWSIG status and nothing else - we
Packit Service 672cf4
         better skip this signature therefore and reuse it for the
Packit Service 672cf4
         next possible signature. */
Packit Service 672cf4
      sig = opd->current_sig;
Packit Service 672cf4
      memset (sig, 0, sizeof *sig);
Packit Service 672cf4
      assert (opd->result.signatures == sig);
Packit Service 672cf4
    }
Packit Service 672cf4
  else
Packit Service 672cf4
    {
Packit Service 672cf4
      sig = calloc (1, sizeof (*sig));
Packit Service 672cf4
      if (!sig)
Packit Service 672cf4
        return gpg_error_from_syserror ();
Packit Service 672cf4
      if (!opd->result.signatures)
Packit Service 672cf4
        opd->result.signatures = sig;
Packit Service 672cf4
      if (opd->current_sig)
Packit Service 672cf4
        opd->current_sig->next = sig;
Packit Service 672cf4
      opd->current_sig = sig;
Packit Service 672cf4
    }
Packit Service 672cf4
  opd->did_prepare_new_sig = 1;
Packit Service 672cf4
  opd->only_newsig_seen = 0;
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
parse_new_sig (op_data_t opd, gpgme_status_code_t code, char *args,
Packit Service 672cf4
               gpgme_protocol_t protocol)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_signature_t sig;
Packit Service 672cf4
  char *end = strchr (args, ' ');
Packit Service 672cf4
  char *tail;
Packit Service 672cf4
Packit Service 672cf4
  if (end)
Packit Service 672cf4
    {
Packit Service 672cf4
      *end = '\0';
Packit Service 672cf4
      end++;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (!opd->did_prepare_new_sig)
Packit Service 672cf4
    {
Packit Service 672cf4
      gpg_error_t err;
Packit Service 672cf4
Packit Service 672cf4
      err = prepare_new_sig (opd);
Packit Service 672cf4
      if (err)
Packit Service 672cf4
        return err;
Packit Service 672cf4
    }
Packit Service 672cf4
  assert (opd->did_prepare_new_sig);
Packit Service 672cf4
  opd->did_prepare_new_sig = 0;
Packit Service 672cf4
Packit Service 672cf4
  assert (opd->current_sig);
Packit Service 672cf4
  sig = opd->current_sig;
Packit Service 672cf4
Packit Service 672cf4
  /* FIXME: We should set the source of the state.  */
Packit Service 672cf4
  switch (code)
Packit Service 672cf4
    {
Packit Service 672cf4
    case GPGME_STATUS_GOODSIG:
Packit Service 672cf4
      sig->status = gpg_error (GPG_ERR_NO_ERROR);
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_STATUS_EXPSIG:
Packit Service 672cf4
      sig->status = gpg_error (GPG_ERR_SIG_EXPIRED);
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_STATUS_EXPKEYSIG:
Packit Service 672cf4
      sig->status = gpg_error (GPG_ERR_KEY_EXPIRED);
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_STATUS_BADSIG:
Packit Service 672cf4
      sig->status = gpg_error (GPG_ERR_BAD_SIGNATURE);
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_STATUS_REVKEYSIG:
Packit Service 672cf4
      sig->status = gpg_error (GPG_ERR_CERT_REVOKED);
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_STATUS_ERRSIG:
Packit Service 672cf4
      /* Parse the pubkey algo.  */
Packit Service 672cf4
      if (!end)
Packit Service 672cf4
	goto parse_err_sig_fail;
Packit Service 672cf4
      gpg_err_set_errno (0);
Packit Service 672cf4
      sig->pubkey_algo = _gpgme_map_pk_algo (strtol (end, &tail, 0), protocol);
Packit Service 672cf4
      if (errno || end == tail || *tail != ' ')
Packit Service 672cf4
	goto parse_err_sig_fail;
Packit Service 672cf4
      end = tail;
Packit Service 672cf4
      while (*end == ' ')
Packit Service 672cf4
	end++;
Packit Service 672cf4
Packit Service 672cf4
      /* Parse the hash algo.  */
Packit Service 672cf4
      if (!*end)
Packit Service 672cf4
	goto parse_err_sig_fail;
Packit Service 672cf4
      gpg_err_set_errno (0);
Packit Service 672cf4
      sig->hash_algo = strtol (end, &tail, 0);
Packit Service 672cf4
      if (errno || end == tail || *tail != ' ')
Packit Service 672cf4
	goto parse_err_sig_fail;
Packit Service 672cf4
      end = tail;
Packit Service 672cf4
      while (*end == ' ')
Packit Service 672cf4
	end++;
Packit Service 672cf4
Packit Service 672cf4
      /* Skip the sig class.  */
Packit Service 672cf4
      end = strchr (end, ' ');
Packit Service 672cf4
      if (!end)
Packit Service 672cf4
	goto parse_err_sig_fail;
Packit Service 672cf4
      while (*end == ' ')
Packit Service 672cf4
	end++;
Packit Service 672cf4
Packit Service 672cf4
      /* Parse the timestamp.  */
Packit Service 672cf4
      sig->timestamp = _gpgme_parse_timestamp (end, &tail);
Packit Service 672cf4
      if (sig->timestamp == -1 || end == tail || (*tail && *tail != ' '))
Packit Service 672cf4
	return trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
      end = tail;
Packit Service 672cf4
      while (*end == ' ')
Packit Service 672cf4
	end++;
Packit Service 672cf4
Packit Service 672cf4
      /* Parse the return code.  */
Packit Service 672cf4
      if (!*end)
Packit Service 672cf4
	goto parse_err_sig_fail;
Packit Service 672cf4
Packit Service 6c01f9
      sig->status = strtoul (end, NULL, 10);
Packit Service 672cf4
      goto parse_err_sig_ok;
Packit Service 672cf4
Packit Service 672cf4
    parse_err_sig_fail:
Packit Service 672cf4
      sig->status = gpg_error (GPG_ERR_GENERAL);
Packit Service 672cf4
    parse_err_sig_ok:
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    default:
Packit Service 672cf4
      return gpg_error (GPG_ERR_GENERAL);
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 6c01f9
  if (*args)
Packit Service 672cf4
    {
Packit Service 672cf4
      sig->fpr = strdup (args);
Packit Service 672cf4
      if (!sig->fpr)
Packit Service 672cf4
	return gpg_error_from_syserror ();
Packit Service 672cf4
    }
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
parse_valid_sig (gpgme_signature_t sig, char *args, gpgme_protocol_t protocol)
Packit Service 672cf4
{
Packit Service 672cf4
  char *end = strchr (args, ' ');
Packit Service 672cf4
  if (end)
Packit Service 672cf4
    {
Packit Service 672cf4
      *end = '\0';
Packit Service 672cf4
      end++;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (!*args)
Packit Service 672cf4
    /* We require at least the fingerprint.  */
Packit Service 672cf4
    return gpg_error (GPG_ERR_GENERAL);
Packit Service 672cf4
Packit Service 672cf4
  if (sig->fpr)
Packit Service 672cf4
    free (sig->fpr);
Packit Service 672cf4
  sig->fpr = strdup (args);
Packit Service 672cf4
  if (!sig->fpr)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
Packit Service 672cf4
  /* Skip the creation date.  */
Packit Service 672cf4
  end = strchr (end, ' ');
Packit Service 672cf4
  if (end)
Packit Service 672cf4
    {
Packit Service 672cf4
      char *tail;
Packit Service 672cf4
Packit Service 672cf4
      sig->timestamp = _gpgme_parse_timestamp (end, &tail);
Packit Service 672cf4
      if (sig->timestamp == -1 || end == tail || (*tail && *tail != ' '))
Packit Service 672cf4
	return trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
      end = tail;
Packit Service 672cf4
Packit Service 672cf4
      sig->exp_timestamp = _gpgme_parse_timestamp (end, &tail);
Packit Service 672cf4
      if (sig->exp_timestamp == -1 || end == tail || (*tail && *tail != ' '))
Packit Service 672cf4
	return trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
      end = tail;
Packit Service 672cf4
Packit Service 672cf4
      while (*end == ' ')
Packit Service 672cf4
	end++;
Packit Service 672cf4
      /* Skip the signature version.  */
Packit Service 672cf4
      end = strchr (end, ' ');
Packit Service 672cf4
      if (end)
Packit Service 672cf4
	{
Packit Service 672cf4
	  while (*end == ' ')
Packit Service 672cf4
	    end++;
Packit Service 672cf4
Packit Service 672cf4
	  /* Skip the reserved field.  */
Packit Service 672cf4
	  end = strchr (end, ' ');
Packit Service 672cf4
	  if (end)
Packit Service 672cf4
	    {
Packit Service 672cf4
	      /* Parse the pubkey algo.  */
Packit Service 672cf4
	      gpg_err_set_errno (0);
Packit Service 672cf4
	      sig->pubkey_algo = _gpgme_map_pk_algo (strtol (end, &tail, 0),
Packit Service 672cf4
                                                     protocol);
Packit Service 672cf4
	      if (errno || end == tail || *tail != ' ')
Packit Service 672cf4
		return trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
	      end = tail;
Packit Service 672cf4
Packit Service 672cf4
	      while (*end == ' ')
Packit Service 672cf4
		end++;
Packit Service 672cf4
Packit Service 672cf4
	      if (*end)
Packit Service 672cf4
		{
Packit Service 672cf4
		  /* Parse the hash algo.  */
Packit Service 672cf4
Packit Service 672cf4
		  gpg_err_set_errno (0);
Packit Service 672cf4
		  sig->hash_algo = strtol (end, &tail, 0);
Packit Service 672cf4
		  if (errno || end == tail || *tail != ' ')
Packit Service 672cf4
		    return trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
		  end = tail;
Packit Service 672cf4
		}
Packit Service 672cf4
	    }
Packit Service 672cf4
	}
Packit Service 672cf4
    }
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
parse_notation (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  gpgme_sig_notation_t *lastp = &sig->notations;
Packit Service 672cf4
  gpgme_sig_notation_t notation = sig->notations;
Packit Service 672cf4
  char *p;
Packit Service 672cf4
Packit Service 672cf4
  if (code == GPGME_STATUS_NOTATION_NAME || code == GPGME_STATUS_POLICY_URL)
Packit Service 672cf4
    {
Packit Service 672cf4
      p = strchr (args, ' ');
Packit Service 672cf4
      if (p)
Packit Service 672cf4
        *p = '\0';
Packit Service 672cf4
Packit Service 672cf4
      /* FIXME: We could keep a pointer to the last notation in the list.  */
Packit Service 672cf4
      while (notation && notation->value)
Packit Service 672cf4
	{
Packit Service 672cf4
	  lastp = &notation->next;
Packit Service 672cf4
	  notation = notation->next;
Packit Service 672cf4
	}
Packit Service 672cf4
Packit Service 672cf4
      if (notation)
Packit Service 672cf4
	/* There is another notation name without data for the
Packit Service 672cf4
	   previous one.  The crypto backend misbehaves.  */
Packit Service 672cf4
	return trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
Packit Service 672cf4
      err = _gpgme_sig_notation_create (&notation, NULL, 0, NULL, 0, 0);
Packit Service 672cf4
      if (err)
Packit Service 672cf4
	return err;
Packit Service 672cf4
Packit Service 672cf4
      if (code == GPGME_STATUS_NOTATION_NAME)
Packit Service 672cf4
	{
Packit Service 672cf4
	  err = _gpgme_decode_percent_string (args, &notation->name, 0, 0);
Packit Service 672cf4
	  if (err)
Packit Service 672cf4
	    {
Packit Service 672cf4
	      _gpgme_sig_notation_free (notation);
Packit Service 672cf4
	      return err;
Packit Service 672cf4
	    }
Packit Service 672cf4
Packit Service 672cf4
	  notation->name_len = strlen (notation->name);
Packit Service 672cf4
Packit Service 672cf4
	  /* Set default flags for use with older gpg versions which
Packit Service 672cf4
           * do not emit a NOTATIONS_FLAG line.  */
Packit Service 672cf4
	  notation->flags = GPGME_SIG_NOTATION_HUMAN_READABLE;
Packit Service 672cf4
	  notation->human_readable = 1;
Packit Service 672cf4
	}
Packit Service 672cf4
      else
Packit Service 672cf4
	{
Packit Service 672cf4
	  /* This is a policy URL.  */
Packit Service 672cf4
Packit Service 672cf4
	  err = _gpgme_decode_percent_string (args, &notation->value, 0, 0);
Packit Service 672cf4
	  if (err)
Packit Service 672cf4
	    {
Packit Service 672cf4
	      _gpgme_sig_notation_free (notation);
Packit Service 672cf4
	      return err;
Packit Service 672cf4
	    }
Packit Service 672cf4
Packit Service 672cf4
	  notation->value_len = strlen (notation->value);
Packit Service 672cf4
	}
Packit Service 672cf4
      *lastp = notation;
Packit Service 672cf4
    }
Packit Service 672cf4
  else if (code == GPGME_STATUS_NOTATION_FLAGS)
Packit Service 672cf4
    {
Packit Service 672cf4
      char *field[2];
Packit Service 672cf4
Packit Service 672cf4
      while (notation && notation->next)
Packit Service 672cf4
	{
Packit Service 672cf4
	  lastp = &notation->next;
Packit Service 672cf4
	  notation = notation->next;
Packit Service 672cf4
	}
Packit Service 672cf4
Packit Service 672cf4
      if (!notation || !notation->name)
Packit Service 672cf4
        { /* There are notation flags without a previous notation name.
Packit Service 672cf4
           * The crypto backend misbehaves.  */
Packit Service 672cf4
          return trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
        }
Packit Service 672cf4
      if (_gpgme_split_fields (args, field, DIM (field)) < 2)
Packit Service 672cf4
        { /* Required args missing.  */
Packit Service 672cf4
          return trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
        }
Packit Service 672cf4
      notation->flags = 0;
Packit Service 672cf4
      if (atoi (field[0]))
Packit Service 672cf4
        {
Packit Service 672cf4
          notation->flags |= GPGME_SIG_NOTATION_CRITICAL;
Packit Service 672cf4
          notation->critical = 1;
Packit Service 672cf4
        }
Packit Service 672cf4
      if (atoi (field[1]))
Packit Service 672cf4
        {
Packit Service 672cf4
          notation->flags |= GPGME_SIG_NOTATION_HUMAN_READABLE;
Packit Service 672cf4
          notation->human_readable = 1;
Packit Service 672cf4
        }
Packit Service 672cf4
    }
Packit Service 672cf4
  else if (code == GPGME_STATUS_NOTATION_DATA)
Packit Service 672cf4
    {
Packit Service 672cf4
      int len = strlen (args) + 1;
Packit Service 672cf4
      char *dest;
Packit Service 672cf4
Packit Service 672cf4
      /* FIXME: We could keep a pointer to the last notation in the list.  */
Packit Service 672cf4
      while (notation && notation->next)
Packit Service 672cf4
	{
Packit Service 672cf4
	  lastp = &notation->next;
Packit Service 672cf4
	  notation = notation->next;
Packit Service 672cf4
	}
Packit Service 672cf4
Packit Service 672cf4
      if (!notation || !notation->name)
Packit Service 672cf4
	/* There is notation data without a previous notation
Packit Service 672cf4
	   name.  The crypto backend misbehaves.  */
Packit Service 672cf4
	return trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
Packit Service 672cf4
      if (!notation->value)
Packit Service 672cf4
	{
Packit Service 672cf4
	  dest = notation->value = malloc (len);
Packit Service 672cf4
	  if (!dest)
Packit Service 672cf4
	    return gpg_error_from_syserror ();
Packit Service 672cf4
	}
Packit Service 672cf4
      else
Packit Service 672cf4
	{
Packit Service 672cf4
	  int cur_len = strlen (notation->value);
Packit Service 672cf4
	  dest = realloc (notation->value, len + strlen (notation->value));
Packit Service 672cf4
	  if (!dest)
Packit Service 672cf4
	    return gpg_error_from_syserror ();
Packit Service 672cf4
	  notation->value = dest;
Packit Service 672cf4
	  dest += cur_len;
Packit Service 672cf4
	}
Packit Service 672cf4
Packit Service 672cf4
      err = _gpgme_decode_percent_string (args, &dest, len, 0);
Packit Service 672cf4
      if (err)
Packit Service 672cf4
	return err;
Packit Service 672cf4
Packit Service 672cf4
      notation->value_len += strlen (dest);
Packit Service 672cf4
    }
Packit Service 672cf4
  else
Packit Service 672cf4
    return trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
parse_trust (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
Packit Service 672cf4
{
Packit Service 672cf4
  char *end = strchr (args, ' ');
Packit Service 672cf4
Packit Service 672cf4
  if (end)
Packit Service 672cf4
    *end = '\0';
Packit Service 672cf4
Packit Service 672cf4
  switch (code)
Packit Service 672cf4
    {
Packit Service 672cf4
    case GPGME_STATUS_TRUST_UNDEFINED:
Packit Service 672cf4
    default:
Packit Service 672cf4
      sig->validity = GPGME_VALIDITY_UNKNOWN;
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_STATUS_TRUST_NEVER:
Packit Service 672cf4
      sig->validity = GPGME_VALIDITY_NEVER;
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_STATUS_TRUST_MARGINAL:
Packit Service 672cf4
      sig->validity = GPGME_VALIDITY_MARGINAL;
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_STATUS_TRUST_FULLY:
Packit Service 672cf4
    case GPGME_STATUS_TRUST_ULTIMATE:
Packit Service 672cf4
      sig->validity = GPGME_VALIDITY_FULL;
Packit Service 672cf4
      break;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  sig->validity_reason = 0;
Packit Service 672cf4
  sig->chain_model = 0;
Packit Service 672cf4
  if (*args)
Packit Service 672cf4
    {
Packit Service 672cf4
      sig->validity_reason = atoi (args);
Packit Service 672cf4
      while (*args && *args != ' ')
Packit Service 672cf4
        args++;
Packit Service 672cf4
      if (*args)
Packit Service 672cf4
        {
Packit Service 672cf4
          while (*args == ' ')
Packit Service 672cf4
            args++;
Packit Service 672cf4
          if (!strncmp (args, "chain", 2) && (args[2] == ' ' || !args[2]))
Packit Service 672cf4
            sig->chain_model = 1;
Packit Service 672cf4
        }
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Parse a TOFU_USER line and put the info into SIG.  */
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
parse_tofu_user (gpgme_signature_t sig, char *args, gpgme_protocol_t protocol)
Packit Service 672cf4
{
Packit Service 672cf4
  gpg_error_t err;
Packit Service 672cf4
  char *tail;
Packit Service 672cf4
  gpgme_user_id_t uid;
Packit Service 672cf4
  gpgme_tofu_info_t ti;
Packit Service 672cf4
  char *fpr = NULL;
Packit Service 672cf4
  char *address = NULL;
Packit Service 672cf4
Packit Service 672cf4
  tail = strchr (args, ' ');
Packit Service 672cf4
  if (!tail || tail == args)
Packit Service 672cf4
    {
Packit Service 672cf4
      err = trace_gpg_error (GPG_ERR_INV_ENGINE);  /* No fingerprint.  */
Packit Service 672cf4
      goto leave;
Packit Service 672cf4
    }
Packit Service 672cf4
  *tail++ = 0;
Packit Service 672cf4
Packit Service 672cf4
  fpr = strdup (args);
Packit Service 672cf4
  if (!fpr)
Packit Service 672cf4
    {
Packit Service 672cf4
      err = gpg_error_from_syserror ();
Packit Service 672cf4
      goto leave;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (sig->key && sig->key->fpr && strcmp (sig->key->fpr, fpr))
Packit Service 672cf4
    {
Packit Service 672cf4
      /* GnuPG since 2.1.17 emits multiple TOFU_USER lines with
Packit Service 672cf4
         different fingerprints in case of conflicts for a signature. */
Packit Service 672cf4
      err = gpg_error (GPG_ERR_DUP_VALUE);
Packit Service 672cf4
      goto leave;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  args = tail;
Packit Service 672cf4
  tail = strchr (args, ' ');
Packit Service 672cf4
  if (tail == args)
Packit Service 672cf4
    {
Packit Service 672cf4
      err = trace_gpg_error (GPG_ERR_INV_ENGINE);  /* No addr-spec.  */
Packit Service 672cf4
      goto leave;
Packit Service 672cf4
    }
Packit Service 672cf4
  if (tail)
Packit Service 672cf4
    *tail = 0;
Packit Service 672cf4
Packit Service 672cf4
  err = _gpgme_decode_percent_string (args, &address, 0, 0);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    goto leave;
Packit Service 672cf4
Packit Service 672cf4
  if (!sig->key)
Packit Service 672cf4
    {
Packit Service 672cf4
      err = _gpgme_key_new (&sig->key);
Packit Service 672cf4
      if (err)
Packit Service 672cf4
        goto leave;
Packit Service 672cf4
      sig->key->fpr = fpr;
Packit Service 672cf4
      sig->key->protocol = protocol;
Packit Service 672cf4
      fpr = NULL;
Packit Service 672cf4
    }
Packit Service 672cf4
  else if (!sig->key->fpr)
Packit Service 672cf4
    {
Packit Service 672cf4
      err = trace_gpg_error (GPG_ERR_INTERNAL);
Packit Service 672cf4
      goto leave;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  err = _gpgme_key_append_name (sig->key, address, 0);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    goto leave;
Packit Service 672cf4
Packit Service 672cf4
  uid = sig->key->_last_uid;
Packit Service 672cf4
  assert (uid);
Packit Service 672cf4
Packit Service 672cf4
  ti = calloc (1, sizeof *ti);
Packit Service 672cf4
  if (!ti)
Packit Service 672cf4
    {
Packit Service 672cf4
      err = gpg_error_from_syserror ();
Packit Service 672cf4
      goto leave;
Packit Service 672cf4
    }
Packit Service 672cf4
  uid->tofu = ti;
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
 leave:
Packit Service 672cf4
  free (fpr);
Packit Service 672cf4
  free (address);
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Parse a TOFU_STATS line and store it in the last tofu info of SIG.
Packit Service 672cf4
 *
Packit Service 672cf4
 *   TOFU_STATS <validity> <sign-count> <encr-count> \
Packit Service 672cf4
 *                         [<policy> [<tm1> <tm2> <tm3> <tm4>]]
Packit Service 672cf4
 */
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
parse_tofu_stats (gpgme_signature_t sig, char *args)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  gpgme_tofu_info_t ti;
Packit Service 672cf4
  char *field[8];
Packit Service 672cf4
  int nfields;
Packit Service 672cf4
  unsigned long uval;
Packit Service 672cf4
Packit Service 672cf4
  if (!sig->key || !sig->key->_last_uid || !(ti = sig->key->_last_uid->tofu))
Packit Service 672cf4
    return trace_gpg_error (GPG_ERR_INV_ENGINE); /* No TOFU_USER seen.  */
Packit Service 672cf4
  if (ti->signfirst || ti->signcount || ti->validity || ti->policy)
Packit Service 672cf4
    return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Already set.  */
Packit Service 672cf4
Packit Service 672cf4
  nfields = _gpgme_split_fields (args, field, DIM (field));
Packit Service 672cf4
  if (nfields < 3)
Packit Service 672cf4
    return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Required args missing.  */
Packit Service 672cf4
Packit Service 672cf4
  /* Note that we allow a value of up to 7 which is what we can store
Packit Service 672cf4
   * in the ti->validity.  */
Packit Service 672cf4
  err = _gpgme_strtoul_field (field[0], &uval);
Packit Service 672cf4
  if (err || uval > 7)
Packit Service 672cf4
    return trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
  ti->validity = uval;
Packit Service 672cf4
Packit Service 672cf4
  /* Parse the sign-count.  */
Packit Service 672cf4
  err = _gpgme_strtoul_field (field[1], &uval);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
  if (uval > USHRT_MAX)
Packit Service 672cf4
    uval = USHRT_MAX;
Packit Service 672cf4
  ti->signcount = uval;
Packit Service 672cf4
Packit Service 672cf4
  /* Parse the encr-count.  */
Packit Service 672cf4
  err = _gpgme_strtoul_field (field[2], &uval);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
  if (uval > USHRT_MAX)
Packit Service 672cf4
    uval = USHRT_MAX;
Packit Service 672cf4
  ti->encrcount = uval;
Packit Service 672cf4
Packit Service 672cf4
  if (nfields == 3)
Packit Service 672cf4
    return 0; /* All mandatory fields parsed.  */
Packit Service 672cf4
Packit Service 672cf4
  /* Parse the policy.  */
Packit Service 672cf4
  if (!strcmp (field[3], "none"))
Packit Service 672cf4
    ti->policy = GPGME_TOFU_POLICY_NONE;
Packit Service 672cf4
  else if (!strcmp (field[3], "auto"))
Packit Service 672cf4
    ti->policy = GPGME_TOFU_POLICY_AUTO;
Packit Service 672cf4
  else if (!strcmp (field[3], "good"))
Packit Service 672cf4
    ti->policy = GPGME_TOFU_POLICY_GOOD;
Packit Service 672cf4
  else if (!strcmp (field[3], "bad"))
Packit Service 672cf4
    ti->policy = GPGME_TOFU_POLICY_BAD;
Packit Service 672cf4
  else if (!strcmp (field[3], "ask"))
Packit Service 672cf4
    ti->policy = GPGME_TOFU_POLICY_ASK;
Packit Service 672cf4
  else /* "unknown" and invalid policy strings.  */
Packit Service 672cf4
    ti->policy = GPGME_TOFU_POLICY_UNKNOWN;
Packit Service 672cf4
Packit Service 672cf4
  if (nfields == 4)
Packit Service 672cf4
    return 0; /* No more optional fields.  */
Packit Service 672cf4
Packit Service 672cf4
  /* Parse first and last seen timestamps (none or both are required).  */
Packit Service 672cf4
  if (nfields < 6)
Packit Service 672cf4
    return trace_gpg_error (GPG_ERR_INV_ENGINE); /* "tm2" missing.  */
Packit Service 672cf4
  err = _gpgme_strtoul_field (field[4], &uval);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
  ti->signfirst = uval;
Packit Service 672cf4
  err = _gpgme_strtoul_field (field[5], &uval);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
  ti->signlast = uval;
Packit Service 672cf4
  if (nfields > 7)
Packit Service 672cf4
    {
Packit Service 672cf4
      /* This condition is only to allow for gpg 2.1.15 - can
Packit Service 672cf4
       * eventually be removed.  */
Packit Service 672cf4
      err = _gpgme_strtoul_field (field[6], &uval);
Packit Service 672cf4
      if (err)
Packit Service 672cf4
        return trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
      ti->encrfirst = uval;
Packit Service 672cf4
      err = _gpgme_strtoul_field (field[7], &uval);
Packit Service 672cf4
      if (err)
Packit Service 672cf4
        return trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
      ti->encrlast = uval;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Parse a TOFU_STATS_LONG line and store it in the last tofu info of SIG.  */
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
parse_tofu_stats_long (gpgme_signature_t sig, char *args, int raw)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  gpgme_tofu_info_t ti;
Packit Service 672cf4
  char *p;
Packit Service 672cf4
Packit Service 672cf4
  if (!sig->key || !sig->key->_last_uid || !(ti = sig->key->_last_uid->tofu))
Packit Service 672cf4
    return trace_gpg_error (GPG_ERR_INV_ENGINE); /* No TOFU_USER seen.  */
Packit Service 672cf4
  if (ti->description)
Packit Service 672cf4
    return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Already set.  */
Packit Service 672cf4
Packit Service 672cf4
  err = _gpgme_decode_percent_string (args, &ti->description, 0, 0);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return err;
Packit Service 672cf4
Packit Service 672cf4
  /* Remove the non-breaking spaces.  */
Packit Service 672cf4
  if (!raw)
Packit Service 672cf4
    {
Packit Service 672cf4
      for (p = ti->description; *p; p++)
Packit Service 672cf4
        if (*p == '~')
Packit Service 672cf4
          *p = ' ';
Packit Service 672cf4
    }
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Parse an error status line and if SET_STATUS is true update the
Packit Service 672cf4
   result status as appropriate.  With SET_STATUS being false, only
Packit Service 672cf4
   check for an error.  */
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
parse_error (gpgme_signature_t sig, char *args, int set_status)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  char *where = strchr (args, ' ');
Packit Service 672cf4
  char *which;
Packit Service 672cf4
Packit Service 672cf4
  if (where)
Packit Service 672cf4
    {
Packit Service 672cf4
      *where = '\0';
Packit Service 672cf4
      which = where + 1;
Packit Service 672cf4
Packit Service 672cf4
      where = strchr (which, ' ');
Packit Service 672cf4
      if (where)
Packit Service 672cf4
	*where = '\0';
Packit Service 672cf4
Packit Service 672cf4
      where = args;
Packit Service 672cf4
    }
Packit Service 672cf4
  else
Packit Service 672cf4
    return trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
Packit Service 672cf4
  err = atoi (which);
Packit Service 672cf4
Packit Service 672cf4
  if (!strcmp (where, "proc_pkt.plaintext")
Packit Service 672cf4
      && gpg_err_code (err) == GPG_ERR_BAD_DATA)
Packit Service 672cf4
    {
Packit Service 672cf4
      /* This indicates a double plaintext.  The only solid way to
Packit Service 672cf4
         handle this is by failing the oepration.  */
Packit Service 672cf4
      return gpg_error (GPG_ERR_BAD_DATA);
Packit Service 672cf4
    }
Packit Service 672cf4
  else if (!set_status)
Packit Service 672cf4
    ;
Packit Service 672cf4
  else if (!strcmp (where, "verify.findkey"))
Packit Service 672cf4
    sig->status = err;
Packit Service 672cf4
  else if (!strcmp (where, "verify.keyusage")
Packit Service 672cf4
	   && gpg_err_code (err) == GPG_ERR_WRONG_KEY_USAGE)
Packit Service 672cf4
    sig->wrong_key_usage = 1;
Packit Service 672cf4
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
gpgme_error_t
Packit Service 672cf4
_gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  void *hook;
Packit Service 672cf4
  op_data_t opd;
Packit Service 672cf4
  gpgme_signature_t sig;
Packit Service 672cf4
  char *end;
Packit Service 672cf4
Packit Service 672cf4
  err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook, -1, NULL);
Packit Service 672cf4
  opd = hook;
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return err;
Packit Service 672cf4
Packit Service 672cf4
  sig = opd->current_sig;
Packit Service 672cf4
Packit Service 672cf4
  switch (code)
Packit Service 672cf4
    {
Packit Service 672cf4
    case GPGME_STATUS_NEWSIG:
Packit Service 672cf4
      if (sig)
Packit Service 672cf4
        calc_sig_summary (sig);
Packit Service 672cf4
      err = prepare_new_sig (opd);
Packit Service 672cf4
      opd->only_newsig_seen = 1;
Packit Service 672cf4
      opd->conflict_user_seen = 0;
Packit Service 672cf4
      return err;
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_STATUS_GOODSIG:
Packit Service 672cf4
    case GPGME_STATUS_EXPSIG:
Packit Service 672cf4
    case GPGME_STATUS_EXPKEYSIG:
Packit Service 672cf4
    case GPGME_STATUS_BADSIG:
Packit Service 672cf4
    case GPGME_STATUS_ERRSIG:
Packit Service 672cf4
    case GPGME_STATUS_REVKEYSIG:
Packit Service 672cf4
      if (sig && !opd->did_prepare_new_sig)
Packit Service 672cf4
	calc_sig_summary (sig);
Packit Service 672cf4
      opd->only_newsig_seen = 0;
Packit Service 672cf4
      return parse_new_sig (opd, code, args, ctx->protocol);
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_STATUS_VALIDSIG:
Packit Service 672cf4
      opd->only_newsig_seen = 0;
Packit Service 672cf4
      return sig ? parse_valid_sig (sig, args, ctx->protocol)
Packit Service 672cf4
	: trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_STATUS_NODATA:
Packit Service 672cf4
      opd->only_newsig_seen = 0;
Packit Service 672cf4
      if (!sig)
Packit Service 672cf4
	return gpg_error (GPG_ERR_NO_DATA);
Packit Service 672cf4
      sig->status = gpg_error (GPG_ERR_NO_DATA);
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_STATUS_UNEXPECTED:
Packit Service 672cf4
      opd->only_newsig_seen = 0;
Packit Service 672cf4
      if (!sig)
Packit Service 672cf4
	return gpg_error (GPG_ERR_GENERAL);
Packit Service 672cf4
      sig->status = gpg_error (GPG_ERR_NO_DATA);
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_STATUS_NOTATION_NAME:
Packit Service 672cf4
    case GPGME_STATUS_NOTATION_FLAGS:
Packit Service 672cf4
    case GPGME_STATUS_NOTATION_DATA:
Packit Service 672cf4
    case GPGME_STATUS_POLICY_URL:
Packit Service 672cf4
      opd->only_newsig_seen = 0;
Packit Service 672cf4
      return sig ? parse_notation (sig, code, args)
Packit Service 672cf4
	: trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_STATUS_TRUST_UNDEFINED:
Packit Service 672cf4
    case GPGME_STATUS_TRUST_NEVER:
Packit Service 672cf4
    case GPGME_STATUS_TRUST_MARGINAL:
Packit Service 672cf4
    case GPGME_STATUS_TRUST_FULLY:
Packit Service 672cf4
    case GPGME_STATUS_TRUST_ULTIMATE:
Packit Service 672cf4
      opd->only_newsig_seen = 0;
Packit Service 672cf4
      return sig ? parse_trust (sig, code, args)
Packit Service 672cf4
	: trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_STATUS_PKA_TRUST_BAD:
Packit Service 672cf4
    case GPGME_STATUS_PKA_TRUST_GOOD:
Packit Service 672cf4
      opd->only_newsig_seen = 0;
Packit Service 672cf4
      /* Check that we only get one of these status codes per
Packit Service 672cf4
         signature; if not the crypto backend misbehaves.  */
Packit Service 672cf4
      if (!sig || sig->pka_trust || sig->pka_address)
Packit Service 672cf4
        return trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
      sig->pka_trust = code == GPGME_STATUS_PKA_TRUST_GOOD? 2 : 1;
Packit Service 672cf4
      end = strchr (args, ' ');
Packit Service 672cf4
      if (end)
Packit Service 672cf4
        *end = 0;
Packit Service 672cf4
      sig->pka_address = strdup (args);
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_STATUS_TOFU_USER:
Packit Service 672cf4
      opd->only_newsig_seen = 0;
Packit Service 672cf4
      if (!sig)
Packit Service 672cf4
        return trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
      err = parse_tofu_user (sig, args, ctx->protocol);
Packit Service 672cf4
      /* gpg emits TOFU User lines for each conflicting key.
Packit Service 672cf4
       * GPGME does not expose this to have a clean API and
Packit Service 672cf4
       * a GPGME user can do a keylisting with the address
Packit Service 672cf4
       * normalisation.
Packit Service 672cf4
       * So when a duplicated TOFU_USER line is encountered
Packit Service 6c01f9
       * we ignore the conflicting tofu stats emited afterwards.
Packit Service 672cf4
       */
Packit Service 672cf4
      if (gpg_err_code (err) == GPG_ERR_DUP_VALUE)
Packit Service 672cf4
        {
Packit Service 672cf4
          opd->conflict_user_seen = 1;
Packit Service 672cf4
          break;
Packit Service 672cf4
        }
Packit Service 672cf4
      opd->conflict_user_seen = 0;
Packit Service 672cf4
      return trace_gpg_error (err);
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_STATUS_TOFU_STATS:
Packit Service 672cf4
      opd->only_newsig_seen = 0;
Packit Service 672cf4
      if (opd->conflict_user_seen)
Packit Service 672cf4
        break;
Packit Service 672cf4
      return sig ? parse_tofu_stats (sig, args)
Packit Service 672cf4
        /*    */ : trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_STATUS_TOFU_STATS_LONG:
Packit Service 672cf4
      opd->only_newsig_seen = 0;
Packit Service 672cf4
      if (opd->conflict_user_seen)
Packit Service 672cf4
        break;
Packit Service 672cf4
      return sig ? parse_tofu_stats_long (sig, args, ctx->raw_description)
Packit Service 672cf4
        /*    */ : trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_STATUS_ERROR:
Packit Service 672cf4
      opd->only_newsig_seen = 0;
Packit Service 672cf4
      /* Some  error stati are informational, so we don't return an
Packit Service 672cf4
         error code if we are not ready to process this status.  */
Packit Service 672cf4
      return parse_error (sig, args, !!sig );
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_STATUS_FAILURE:
Packit Service 672cf4
      opd->failure_code = _gpgme_parse_failure (args);
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_STATUS_EOF:
Packit Service 672cf4
      if (sig && !opd->did_prepare_new_sig)
Packit Service 672cf4
	calc_sig_summary (sig);
Packit Service 672cf4
      if (opd->only_newsig_seen && sig)
Packit Service 672cf4
        {
Packit Service 672cf4
          gpgme_signature_t sig2;
Packit Service 672cf4
          /* The last signature has no valid information - remove it
Packit Service 672cf4
             from the list. */
Packit Service 672cf4
          assert (!sig->next);
Packit Service 672cf4
          if (sig == opd->result.signatures)
Packit Service 672cf4
            opd->result.signatures = NULL;
Packit Service 672cf4
          else
Packit Service 672cf4
            {
Packit Service 672cf4
              for (sig2 = opd->result.signatures; sig2; sig2 = sig2->next)
Packit Service 672cf4
                if (sig2->next == sig)
Packit Service 672cf4
                  {
Packit Service 672cf4
                    sig2->next = NULL;
Packit Service 672cf4
                    break;
Packit Service 672cf4
                  }
Packit Service 672cf4
            }
Packit Service 672cf4
          /* Note that there is no need to release the members of SIG
Packit Service 672cf4
             because we won't be here if they have been set. */
Packit Service 672cf4
          free (sig);
Packit Service 672cf4
          opd->current_sig = NULL;
Packit Service 672cf4
        }
Packit Service 672cf4
      opd->only_newsig_seen = 0;
Packit Service 672cf4
      if (opd->failure_code)
Packit Service 672cf4
        return opd->failure_code;
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_STATUS_PLAINTEXT:
Packit Service 672cf4
      if (++opd->plaintext_seen > 1)
Packit Service 672cf4
        return gpg_error (GPG_ERR_BAD_DATA);
Packit Service 6c01f9
      err = _gpgme_parse_plaintext (args, &opd->result.file_name);
Packit Service 6c01f9
      if (err)
Packit Service 6c01f9
	return err;
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_STATUS_VERIFICATION_COMPLIANCE_MODE:
Packit Service 672cf4
      PARSE_COMPLIANCE_FLAGS (args, opd->current_sig);
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    default:
Packit Service 672cf4
      break;
Packit Service 672cf4
    }
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  err = _gpgme_progress_status_handler (priv, code, args);
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = _gpgme_verify_status_handler (priv, code, args);
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
gpgme_error_t
Packit Service 672cf4
_gpgme_op_verify_init_result (gpgme_ctx_t ctx)
Packit Service 672cf4
{
Packit Service 672cf4
  void *hook;
Packit Service 672cf4
  op_data_t opd;
Packit Service 672cf4
Packit Service 672cf4
  return _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook,
Packit Service 672cf4
				sizeof (*opd), release_op_data);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
verify_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t sig,
Packit Service 672cf4
	      gpgme_data_t signed_text, gpgme_data_t plaintext)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  err = _gpgme_op_reset (ctx, synchronous);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return err;
Packit Service 672cf4
Packit Service 672cf4
  err = _gpgme_op_verify_init_result (ctx);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return err;
Packit Service 672cf4
Packit Service 672cf4
  _gpgme_engine_set_status_handler (ctx->engine, verify_status_handler, ctx);
Packit Service 672cf4
Packit Service 672cf4
  if (!sig)
Packit Service 672cf4
    return gpg_error (GPG_ERR_NO_DATA);
Packit Service 672cf4
Packit Service 672cf4
  return _gpgme_engine_op_verify (ctx->engine, sig, signed_text, plaintext,
Packit Service 672cf4
                                  ctx);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Decrypt ciphertext CIPHER and make a signature verification within
Packit Service 672cf4
   CTX and store the resulting plaintext in PLAIN.  */
Packit Service 672cf4
gpgme_error_t
Packit Service 672cf4
gpgme_op_verify_start (gpgme_ctx_t ctx, gpgme_data_t sig,
Packit Service 672cf4
		       gpgme_data_t signed_text, gpgme_data_t plaintext)
Packit Service 672cf4
{
Packit Service 672cf4
  gpg_error_t err;
Packit Service 6c01f9
  TRACE_BEG3 (DEBUG_CTX, "gpgme_op_verify_start", ctx,
Packit Service 672cf4
	      "sig=%p, signed_text=%p, plaintext=%p",
Packit Service 672cf4
	      sig, signed_text, plaintext);
Packit Service 672cf4
Packit Service 672cf4
  if (!ctx)
Packit Service 672cf4
    return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
Packit Service 672cf4
Packit Service 672cf4
  err = verify_start (ctx, 0, sig, signed_text, plaintext);
Packit Service 672cf4
  return TRACE_ERR (err);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Decrypt ciphertext CIPHER and make a signature verification within
Packit Service 672cf4
   CTX and store the resulting plaintext in PLAIN.  */
Packit Service 672cf4
gpgme_error_t
Packit Service 672cf4
gpgme_op_verify (gpgme_ctx_t ctx, gpgme_data_t sig, gpgme_data_t signed_text,
Packit Service 672cf4
		 gpgme_data_t plaintext)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 6c01f9
  TRACE_BEG3 (DEBUG_CTX, "gpgme_op_verify", ctx,
Packit Service 672cf4
	      "sig=%p, signed_text=%p, plaintext=%p",
Packit Service 672cf4
	      sig, signed_text, plaintext);
Packit Service 672cf4
Packit Service 672cf4
  if (!ctx)
Packit Service 672cf4
    return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
Packit Service 672cf4
Packit Service 672cf4
  err = verify_start (ctx, 1, sig, signed_text, plaintext);
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = _gpgme_wait_one (ctx);
Packit Service 672cf4
  return TRACE_ERR (err);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4

Packit Service 672cf4
/* Compatibility interfaces.  */
Packit Service 672cf4
Packit Service 672cf4
/* Get the key used to create signature IDX in CTX and return it in
Packit Service 672cf4
   R_KEY.  */
Packit Service 672cf4
gpgme_error_t
Packit Service 672cf4
gpgme_get_sig_key (gpgme_ctx_t ctx, int idx, gpgme_key_t *r_key)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_verify_result_t result;
Packit Service 672cf4
  gpgme_signature_t sig;
Packit Service 672cf4
Packit Service 672cf4
  if (!ctx)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
  result = gpgme_op_verify_result (ctx);
Packit Service 672cf4
  sig = result->signatures;
Packit Service 672cf4
Packit Service 672cf4
  while (sig && idx)
Packit Service 672cf4
    {
Packit Service 672cf4
      sig = sig->next;
Packit Service 672cf4
      idx--;
Packit Service 672cf4
    }
Packit Service 672cf4
  if (!sig || idx)
Packit Service 672cf4
    return gpg_error (GPG_ERR_EOF);
Packit Service 672cf4
Packit Service 672cf4
  return gpgme_get_key (ctx, sig->fpr, r_key, 0);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Retrieve the signature status of signature IDX in CTX after a
Packit Service 672cf4
   successful verify operation in R_STAT (if non-null).  The creation
Packit Service 672cf4
   time stamp of the signature is returned in R_CREATED (if non-null).
Packit Service 672cf4
   The function returns a string containing the fingerprint.  */
Packit Service 672cf4
const char *
Packit Service 672cf4
gpgme_get_sig_status (gpgme_ctx_t ctx, int idx,
Packit Service 672cf4
                      _gpgme_sig_stat_t *r_stat, time_t *r_created)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_verify_result_t result;
Packit Service 672cf4
  gpgme_signature_t sig;
Packit Service 672cf4
Packit Service 672cf4
  result = gpgme_op_verify_result (ctx);
Packit Service 672cf4
  sig = result->signatures;
Packit Service 672cf4
Packit Service 672cf4
  while (sig && idx)
Packit Service 672cf4
    {
Packit Service 672cf4
      sig = sig->next;
Packit Service 672cf4
      idx--;
Packit Service 672cf4
    }
Packit Service 672cf4
  if (!sig || idx)
Packit Service 672cf4
    return NULL;
Packit Service 672cf4
Packit Service 672cf4
  if (r_stat)
Packit Service 672cf4
    {
Packit Service 672cf4
      switch (gpg_err_code (sig->status))
Packit Service 672cf4
	{
Packit Service 672cf4
	case GPG_ERR_NO_ERROR:
Packit Service 672cf4
	  *r_stat = GPGME_SIG_STAT_GOOD;
Packit Service 672cf4
	  break;
Packit Service 672cf4
Packit Service 672cf4
	case GPG_ERR_BAD_SIGNATURE:
Packit Service 672cf4
	  *r_stat = GPGME_SIG_STAT_BAD;
Packit Service 672cf4
	  break;
Packit Service 672cf4
Packit Service 672cf4
	case GPG_ERR_NO_PUBKEY:
Packit Service 672cf4
	  *r_stat = GPGME_SIG_STAT_NOKEY;
Packit Service 672cf4
	  break;
Packit Service 672cf4
Packit Service 672cf4
	case GPG_ERR_NO_DATA:
Packit Service 672cf4
	  *r_stat = GPGME_SIG_STAT_NOSIG;
Packit Service 672cf4
	  break;
Packit Service 672cf4
Packit Service 672cf4
	case GPG_ERR_SIG_EXPIRED:
Packit Service 672cf4
	  *r_stat = GPGME_SIG_STAT_GOOD_EXP;
Packit Service 672cf4
	  break;
Packit Service 672cf4
Packit Service 672cf4
	case GPG_ERR_KEY_EXPIRED:
Packit Service 672cf4
	  *r_stat = GPGME_SIG_STAT_GOOD_EXPKEY;
Packit Service 672cf4
	  break;
Packit Service 672cf4
Packit Service 672cf4
	default:
Packit Service 672cf4
	  *r_stat = GPGME_SIG_STAT_ERROR;
Packit Service 672cf4
	  break;
Packit Service 672cf4
	}
Packit Service 672cf4
    }
Packit Service 672cf4
  if (r_created)
Packit Service 672cf4
    *r_created = sig->timestamp;
Packit Service 672cf4
  return sig->fpr;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Retrieve certain attributes of a signature.  IDX is the index
Packit Service 672cf4
   number of the signature after a successful verify operation.  WHAT
Packit Service 672cf4
   is an attribute where GPGME_ATTR_EXPIRE is probably the most useful
Packit Service 672cf4
   one.  WHATIDX is to be passed as 0 for most attributes . */
Packit Service 672cf4
unsigned long
Packit Service 672cf4
gpgme_get_sig_ulong_attr (gpgme_ctx_t ctx, int idx,
Packit Service 672cf4
                          _gpgme_attr_t what, int whatidx)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_verify_result_t result;
Packit Service 672cf4
  gpgme_signature_t sig;
Packit Service 672cf4
Packit Service 672cf4
  (void)whatidx;
Packit Service 672cf4
Packit Service 672cf4
  result = gpgme_op_verify_result (ctx);
Packit Service 672cf4
  sig = result->signatures;
Packit Service 672cf4
Packit Service 672cf4
  while (sig && idx)
Packit Service 672cf4
    {
Packit Service 672cf4
      sig = sig->next;
Packit Service 672cf4
      idx--;
Packit Service 672cf4
    }
Packit Service 672cf4
  if (!sig || idx)
Packit Service 672cf4
    return 0;
Packit Service 672cf4
Packit Service 672cf4
  switch (what)
Packit Service 672cf4
    {
Packit Service 672cf4
    case GPGME_ATTR_CREATED:
Packit Service 672cf4
      return sig->timestamp;
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_ATTR_EXPIRE:
Packit Service 672cf4
      return sig->exp_timestamp;
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_ATTR_VALIDITY:
Packit Service 672cf4
      return (unsigned long) sig->validity;
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_ATTR_SIG_STATUS:
Packit Service 672cf4
      switch (gpg_err_code (sig->status))
Packit Service 672cf4
	{
Packit Service 672cf4
	case GPG_ERR_NO_ERROR:
Packit Service 672cf4
	  return GPGME_SIG_STAT_GOOD;
Packit Service 672cf4
Packit Service 672cf4
	case GPG_ERR_BAD_SIGNATURE:
Packit Service 672cf4
	  return GPGME_SIG_STAT_BAD;
Packit Service 672cf4
Packit Service 672cf4
	case GPG_ERR_NO_PUBKEY:
Packit Service 672cf4
	  return GPGME_SIG_STAT_NOKEY;
Packit Service 672cf4
Packit Service 672cf4
	case GPG_ERR_NO_DATA:
Packit Service 672cf4
	  return GPGME_SIG_STAT_NOSIG;
Packit Service 672cf4
Packit Service 672cf4
	case GPG_ERR_SIG_EXPIRED:
Packit Service 672cf4
	  return GPGME_SIG_STAT_GOOD_EXP;
Packit Service 672cf4
Packit Service 672cf4
	case GPG_ERR_KEY_EXPIRED:
Packit Service 672cf4
	  return GPGME_SIG_STAT_GOOD_EXPKEY;
Packit Service 672cf4
Packit Service 672cf4
	default:
Packit Service 672cf4
	  return GPGME_SIG_STAT_ERROR;
Packit Service 672cf4
	}
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_ATTR_SIG_SUMMARY:
Packit Service 672cf4
      return sig->summary;
Packit Service 672cf4
Packit Service 672cf4
    default:
Packit Service 672cf4
      break;
Packit Service 672cf4
    }
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
const char *
Packit Service 672cf4
gpgme_get_sig_string_attr (gpgme_ctx_t ctx, int idx,
Packit Service 672cf4
                           _gpgme_attr_t what, int whatidx)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_verify_result_t result;
Packit Service 672cf4
  gpgme_signature_t sig;
Packit Service 672cf4
Packit Service 672cf4
  result = gpgme_op_verify_result (ctx);
Packit Service 672cf4
  sig = result->signatures;
Packit Service 672cf4
Packit Service 672cf4
  while (sig && idx)
Packit Service 672cf4
    {
Packit Service 672cf4
      sig = sig->next;
Packit Service 672cf4
      idx--;
Packit Service 672cf4
    }
Packit Service 672cf4
  if (!sig || idx)
Packit Service 672cf4
    return NULL;
Packit Service 672cf4
Packit Service 672cf4
  switch (what)
Packit Service 672cf4
    {
Packit Service 672cf4
    case GPGME_ATTR_FPR:
Packit Service 672cf4
      return sig->fpr;
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_ATTR_ERRTOK:
Packit Service 672cf4
      if (whatidx == 1)
Packit Service 672cf4
        return sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
Packit Service 672cf4
      else
Packit Service 672cf4
	return "";
Packit Service 672cf4
    default:
Packit Service 672cf4
      break;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  return NULL;
Packit Service 672cf4
}