LCOV - code coverage report
Current view: top level - src - verify.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 423 657 64.4 %
Date: 2018-11-15 08:49:49 Functions: 18 22 81.8 %

          Line data    Source code
       1             : /* verify.c - Signature verification.
       2             :    Copyright (C) 2000 Werner Koch (dd9jn)
       3             :    Copyright (C) 2001, 2002, 2003, 2004, 2005 g10 Code GmbH
       4             : 
       5             :    This file is part of GPGME.
       6             : 
       7             :    GPGME is free software; you can redistribute it and/or modify it
       8             :    under the terms of the GNU Lesser General Public License as
       9             :    published by the Free Software Foundation; either version 2.1 of
      10             :    the License, or (at your option) any later version.
      11             : 
      12             :    GPGME is distributed in the hope that it will be useful, but
      13             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :    Lesser General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU Lesser General Public
      18             :    License along with this program; if not, write to the Free Software
      19             :    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
      20             :    02111-1307, USA.  */
      21             : 
      22             : #if HAVE_CONFIG_H
      23             : #include <config.h>
      24             : #endif
      25             : #include <stdlib.h>
      26             : #include <string.h>
      27             : #include <errno.h>
      28             : #include <assert.h>
      29             : #include <limits.h>
      30             : 
      31             : #include "gpgme.h"
      32             : #include "debug.h"
      33             : #include "util.h"
      34             : #include "context.h"
      35             : #include "ops.h"
      36             : 
      37             : 
      38             : typedef struct
      39             : {
      40             :   struct _gpgme_op_verify_result result;
      41             : 
      42             :   /* The error code from a FAILURE status line or 0.  */
      43             :   gpg_error_t failure_code;
      44             : 
      45             :   gpgme_signature_t current_sig;
      46             :   int did_prepare_new_sig;
      47             :   int only_newsig_seen;
      48             :   int plaintext_seen;
      49             :   int conflict_user_seen;
      50             : } *op_data_t;
      51             : 
      52             : 
      53             : static void
      54          76 : release_op_data (void *hook)
      55             : {
      56          76 :   op_data_t opd = (op_data_t) hook;
      57          76 :   gpgme_signature_t sig = opd->result.signatures;
      58             : 
      59         215 :   while (sig)
      60             :     {
      61          63 :       gpgme_signature_t next = sig->next;
      62          63 :       gpgme_sig_notation_t notation = sig->notations;
      63             : 
      64         195 :       while (notation)
      65             :         {
      66          69 :           gpgme_sig_notation_t next_nota = notation->next;
      67             : 
      68          69 :           _gpgme_sig_notation_free (notation);
      69          69 :           notation = next_nota;
      70             :         }
      71             : 
      72          63 :       if (sig->fpr)
      73          63 :         free (sig->fpr);
      74          63 :       if (sig->pka_address)
      75           0 :         free (sig->pka_address);
      76          63 :       if (sig->key)
      77          11 :         gpgme_key_unref (sig->key);
      78          63 :       free (sig);
      79          63 :       sig = next;
      80             :     }
      81             : 
      82          76 :   if (opd->result.file_name)
      83          23 :     free (opd->result.file_name);
      84          76 : }
      85             : 
      86             : 
      87             : gpgme_verify_result_t
      88          75 : gpgme_op_verify_result (gpgme_ctx_t ctx)
      89             : {
      90             :   void *hook;
      91             :   op_data_t opd;
      92             :   gpgme_error_t err;
      93             :   gpgme_signature_t sig;
      94             : 
      95          75 :   TRACE_BEG (DEBUG_CTX, "gpgme_op_verify_result", ctx);
      96          75 :   err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook, -1, NULL);
      97          75 :   opd = hook;
      98          75 :   if (err || !opd)
      99             :     {
     100           0 :       TRACE_SUC0 ("result=(null)");
     101           0 :       return NULL;
     102             :     }
     103             : 
     104             :   /* It is possible that we saw a new signature only followed by an
     105             :      ERROR line for that.  In particular a missing X.509 key triggers
     106             :      this.  In this case it is surprising that the summary field has
     107             :      not been updated.  We fix it here by explicitly looking for this
     108             :      case.  The real fix would be to have GPGME emit ERRSIG.  */
     109         142 :   for (sig = opd->result.signatures; sig; sig = sig->next)
     110             :     {
     111          67 :       if (!sig->summary)
     112             :         {
     113          32 :           switch (gpg_err_code (sig->status))
     114             :             {
     115             :             case GPG_ERR_KEY_EXPIRED:
     116           0 :               sig->summary |= GPGME_SIGSUM_KEY_EXPIRED;
     117           0 :               break;
     118             : 
     119             :             case GPG_ERR_NO_PUBKEY:
     120           0 :               sig->summary |= GPGME_SIGSUM_KEY_MISSING;
     121           0 :               break;
     122             : 
     123             :             default:
     124          32 :               break;
     125             :             }
     126             :         }
     127             :     }
     128             : 
     129             :   /* Now for some tracing stuff. */
     130             :   if (_gpgme_debug_trace ())
     131             :     {
     132             :       int i;
     133             : 
     134         142 :       for (sig = opd->result.signatures, i = 0; sig; sig = sig->next, i++)
     135             :         {
     136          67 :           TRACE_LOG4 ("sig[%i] = fpr %s, summary 0x%x, status %s",
     137             :                       i, sig->fpr, sig->summary, gpg_strerror (sig->status));
     138          67 :           TRACE_LOG6 ("sig[%i] = timestamps 0x%x/0x%x flags:%s%s%s",
     139             :                       i, sig->timestamp, sig->exp_timestamp,
     140             :                       sig->wrong_key_usage ? "wrong key usage" : "",
     141             :                       sig->pka_trust == 1 ? "pka bad"
     142             :                       : (sig->pka_trust == 2 ? "pka_okay" : "pka RFU"),
     143             :                       sig->chain_model ? "chain model" : "");
     144          67 :           TRACE_LOG5 ("sig[%i] = validity 0x%x (%s), algos %s/%s",
     145             :                       i, sig->validity, gpg_strerror (sig->validity_reason),
     146             :                       gpgme_pubkey_algo_name (sig->pubkey_algo),
     147             :                       gpgme_hash_algo_name (sig->hash_algo));
     148          67 :           if (sig->pka_address)
     149             :             {
     150           0 :               TRACE_LOG2 ("sig[%i] = PKA address %s", i, sig->pka_address);
     151             :             }
     152          67 :           if (sig->notations)
     153             :             {
     154          25 :               TRACE_LOG1 ("sig[%i] = has notations (not shown)", i);
     155             :             }
     156             :         }
     157             :     }
     158             : 
     159          75 :   TRACE_SUC1 ("result=%p", &opd->result);
     160          75 :   return &opd->result;
     161             : }
     162             : 
     163             : 
     164             : /* Build a summary vector from RESULT. */
     165             : static void
     166          68 : calc_sig_summary (gpgme_signature_t sig)
     167             : {
     168          68 :   unsigned long sum = 0;
     169             : 
     170             :   /* Calculate the red/green flag.  */
     171          68 :   if (sig->validity == GPGME_VALIDITY_FULL
     172          40 :       || sig->validity == GPGME_VALIDITY_ULTIMATE)
     173             :     {
     174          56 :       if (gpg_err_code (sig->status) == GPG_ERR_NO_ERROR
     175           0 :           || gpg_err_code (sig->status) == GPG_ERR_SIG_EXPIRED
     176           0 :           || gpg_err_code (sig->status) == GPG_ERR_KEY_EXPIRED)
     177          28 :         sum |= GPGME_SIGSUM_GREEN;
     178             :     }
     179          40 :   else if (sig->validity == GPGME_VALIDITY_NEVER)
     180             :     {
     181           0 :       if (gpg_err_code (sig->status) == GPG_ERR_NO_ERROR
     182           0 :           || gpg_err_code (sig->status) == GPG_ERR_SIG_EXPIRED
     183           0 :           || gpg_err_code (sig->status) == GPG_ERR_KEY_EXPIRED)
     184           0 :         sum |= GPGME_SIGSUM_RED;
     185             :     }
     186          40 :   else if (gpg_err_code (sig->status) == GPG_ERR_BAD_SIGNATURE)
     187           6 :     sum |= GPGME_SIGSUM_RED;
     188             : 
     189             : 
     190             :   /* FIXME: handle the case when key and message are expired. */
     191          68 :   switch (gpg_err_code (sig->status))
     192             :     {
     193             :     case GPG_ERR_SIG_EXPIRED:
     194           0 :       sum |= GPGME_SIGSUM_SIG_EXPIRED;
     195           0 :       break;
     196             : 
     197             :     case GPG_ERR_KEY_EXPIRED:
     198           0 :       sum |= GPGME_SIGSUM_KEY_EXPIRED;
     199           0 :       break;
     200             : 
     201             :     case GPG_ERR_NO_PUBKEY:
     202           1 :       sum |= GPGME_SIGSUM_KEY_MISSING;
     203           1 :       break;
     204             : 
     205             :     case GPG_ERR_CERT_REVOKED:
     206           0 :       sum |= GPGME_SIGSUM_KEY_REVOKED;
     207           0 :       break;
     208             : 
     209             :     case GPG_ERR_BAD_SIGNATURE:
     210             :     case GPG_ERR_NO_ERROR:
     211          67 :       break;
     212             : 
     213             :     default:
     214           0 :       sum |= GPGME_SIGSUM_SYS_ERROR;
     215           0 :       break;
     216             :     }
     217             : 
     218             :   /* Now look at the certain reason codes.  */
     219          68 :   switch (gpg_err_code (sig->validity_reason))
     220             :     {
     221             :     case GPG_ERR_CRL_TOO_OLD:
     222           0 :       if (sig->validity == GPGME_VALIDITY_UNKNOWN)
     223           0 :         sum |= GPGME_SIGSUM_CRL_TOO_OLD;
     224           0 :       break;
     225             : 
     226             :     case GPG_ERR_CERT_REVOKED:
     227             :       /* Note that this is a second way to set this flag.  It may also
     228             :          have been set due to a sig->status of STATUS_REVKEYSIG from
     229             :          parse_new_sig.  */
     230           0 :       sum |= GPGME_SIGSUM_KEY_REVOKED;
     231           0 :       break;
     232             : 
     233             :     default:
     234          68 :       break;
     235             :     }
     236             : 
     237             :   /* Check other flags. */
     238          68 :   if (sig->wrong_key_usage)
     239           0 :     sum |= GPGME_SIGSUM_BAD_POLICY;
     240             : 
     241             :   /* Set the valid flag when the signature is unquestionable
     242             :      valid.  (The test is identical to if(sum == GPGME_SIGSUM_GREEN)). */
     243          68 :   if ((sum & GPGME_SIGSUM_GREEN) && !(sum & ~GPGME_SIGSUM_GREEN))
     244          28 :     sum |= GPGME_SIGSUM_VALID;
     245             : 
     246          68 :   sig->summary = sum;
     247          68 : }
     248             : 
     249             : 
     250             : static gpgme_error_t
     251          64 : prepare_new_sig (op_data_t opd)
     252             : {
     253             :   gpgme_signature_t sig;
     254             : 
     255          64 :   if (opd->only_newsig_seen && opd->current_sig)
     256             :     {
     257             :       /* We have only seen the NEWSIG status and nothing else - we
     258             :          better skip this signature therefore and reuse it for the
     259             :          next possible signature. */
     260           0 :       sig = opd->current_sig;
     261           0 :       memset (sig, 0, sizeof *sig);
     262           0 :       assert (opd->result.signatures == sig);
     263             :     }
     264             :   else
     265             :     {
     266          64 :       sig = calloc (1, sizeof (*sig));
     267          64 :       if (!sig)
     268           0 :         return gpg_error_from_syserror ();
     269          64 :       if (!opd->result.signatures)
     270          63 :         opd->result.signatures = sig;
     271          64 :       if (opd->current_sig)
     272           1 :         opd->current_sig->next = sig;
     273          64 :       opd->current_sig = sig;
     274             :     }
     275          64 :   opd->did_prepare_new_sig = 1;
     276          64 :   opd->only_newsig_seen = 0;
     277          64 :   return 0;
     278             : }
     279             : 
     280             : static gpgme_error_t
     281          67 : parse_new_sig (op_data_t opd, gpgme_status_code_t code, char *args,
     282             :                gpgme_protocol_t protocol)
     283             : {
     284             :   gpgme_signature_t sig;
     285          67 :   char *end = strchr (args, ' ');
     286             :   char *tail;
     287          67 :   int got_fpr = 0;
     288             : 
     289          67 :   if (end)
     290             :     {
     291          67 :       *end = '\0';
     292          67 :       end++;
     293             :     }
     294             : 
     295          67 :   if (!opd->did_prepare_new_sig)
     296             :     {
     297             :       gpg_error_t err;
     298             : 
     299           0 :       err = prepare_new_sig (opd);
     300           0 :       if (err)
     301           0 :         return err;
     302             :     }
     303          67 :   assert (opd->did_prepare_new_sig);
     304          67 :   opd->did_prepare_new_sig = 0;
     305             : 
     306          67 :   assert (opd->current_sig);
     307          67 :   sig = opd->current_sig;
     308             : 
     309             :   /* FIXME: We should set the source of the state.  */
     310          67 :   switch (code)
     311             :     {
     312             :     case GPGME_STATUS_GOODSIG:
     313          60 :       sig->status = gpg_error (GPG_ERR_NO_ERROR);
     314          57 :       break;
     315             : 
     316             :     case GPGME_STATUS_EXPSIG:
     317           0 :       sig->status = gpg_error (GPG_ERR_SIG_EXPIRED);
     318           0 :       break;
     319             : 
     320             :     case GPGME_STATUS_EXPKEYSIG:
     321           0 :       sig->status = gpg_error (GPG_ERR_KEY_EXPIRED);
     322           0 :       break;
     323             : 
     324             :     case GPGME_STATUS_BADSIG:
     325           6 :       sig->status = gpg_error (GPG_ERR_BAD_SIGNATURE);
     326           6 :       break;
     327             : 
     328             :     case GPGME_STATUS_REVKEYSIG:
     329           0 :       sig->status = gpg_error (GPG_ERR_CERT_REVOKED);
     330           0 :       break;
     331             : 
     332             :     case GPGME_STATUS_ERRSIG:
     333             :       /* Parse the pubkey algo.  */
     334           1 :       if (!end)
     335           0 :         goto parse_err_sig_fail;
     336           1 :       gpg_err_set_errno (0);
     337           1 :       sig->pubkey_algo = _gpgme_map_pk_algo (strtol (end, &tail, 0), protocol);
     338           1 :       if (errno || end == tail || *tail != ' ')
     339             :         goto parse_err_sig_fail;
     340           1 :       end = tail;
     341           3 :       while (*end == ' ')
     342           1 :         end++;
     343             : 
     344             :       /* Parse the hash algo.  */
     345           1 :       if (!*end)
     346           0 :         goto parse_err_sig_fail;
     347           1 :       gpg_err_set_errno (0);
     348           1 :       sig->hash_algo = strtol (end, &tail, 0);
     349           1 :       if (errno || end == tail || *tail != ' ')
     350             :         goto parse_err_sig_fail;
     351           1 :       end = tail;
     352           3 :       while (*end == ' ')
     353           1 :         end++;
     354             : 
     355             :       /* Skip the sig class.  */
     356           1 :       end = strchr (end, ' ');
     357           1 :       if (!end)
     358           0 :         goto parse_err_sig_fail;
     359           3 :       while (*end == ' ')
     360           1 :         end++;
     361             : 
     362             :       /* Parse the timestamp.  */
     363           1 :       sig->timestamp = _gpgme_parse_timestamp (end, &tail);
     364           1 :       if (sig->timestamp == -1 || end == tail || (*tail && *tail != ' '))
     365           0 :         return trace_gpg_error (GPG_ERR_INV_ENGINE);
     366           1 :       end = tail;
     367           3 :       while (*end == ' ')
     368           1 :         end++;
     369             : 
     370             :       /* Parse the return code.  */
     371           1 :       if (!*end)
     372           0 :         goto parse_err_sig_fail;
     373             : 
     374           1 :       gpg_err_set_errno (0);
     375           1 :       sig->status = strtoul (end, &tail, 10);
     376           1 :       if (errno || end == tail || (*tail && *tail != ' '))
     377             :         goto parse_err_sig_fail;
     378           1 :       if (!*tail)
     379           0 :         goto parse_err_sig_ok;
     380           1 :       end = tail;
     381           3 :       while (*end == ' ')
     382           1 :         end++;
     383             : 
     384             :       /* Parse the new fingerprint (from the ISSUER_FPR subpacket).  */
     385           1 :       if (!*end || (*end == '-' && (end[1] == ' ' || !end[1])))
     386             :         goto parse_err_sig_ok;  /* Okay (just trailing spaces).  */
     387           1 :       sig->fpr = strdup (end);
     388           1 :       if (!sig->fpr)
     389           0 :         return gpg_error_from_syserror ();
     390           1 :       got_fpr = 1;
     391           1 :       goto parse_err_sig_ok;
     392             : 
     393             :     parse_err_sig_fail:
     394           0 :       sig->status = gpg_error (GPG_ERR_GENERAL);
     395             :     parse_err_sig_ok:
     396           1 :       break;
     397             : 
     398             :     default:
     399           0 :       return gpg_error (GPG_ERR_GENERAL);
     400             :     }
     401             : 
     402          64 :   if (*args && !got_fpr)
     403             :     {
     404          66 :       sig->fpr = strdup (args);
     405          66 :       if (!sig->fpr)
     406           0 :         return gpg_error_from_syserror ();
     407             :     }
     408          64 :   return 0;
     409             : }
     410             : 
     411             : 
     412             : static gpgme_error_t
     413          57 : parse_valid_sig (gpgme_signature_t sig, char *args, gpgme_protocol_t protocol)
     414             : {
     415          57 :   char *end = strchr (args, ' ');
     416          57 :   if (end)
     417             :     {
     418          58 :       *end = '\0';
     419          58 :       end++;
     420             :     }
     421             : 
     422          57 :   if (!*args)
     423             :     /* We require at least the fingerprint.  */
     424           0 :     return gpg_error (GPG_ERR_GENERAL);
     425             : 
     426          57 :   if (sig->fpr)
     427          58 :     free (sig->fpr);
     428          57 :   sig->fpr = strdup (args);
     429          57 :   if (!sig->fpr)
     430           0 :     return gpg_error_from_syserror ();
     431             : 
     432             :   /* Skip the creation date.  */
     433          57 :   end = strchr (end, ' ');
     434          57 :   if (end)
     435             :     {
     436             :       char *tail;
     437             : 
     438          58 :       sig->timestamp = _gpgme_parse_timestamp (end, &tail);
     439          57 :       if (sig->timestamp == -1 || end == tail || (*tail && *tail != ' '))
     440           0 :         return trace_gpg_error (GPG_ERR_INV_ENGINE);
     441          57 :       end = tail;
     442             : 
     443          57 :       sig->exp_timestamp = _gpgme_parse_timestamp (end, &tail);
     444          57 :       if (sig->exp_timestamp == -1 || end == tail || (*tail && *tail != ' '))
     445           0 :         return trace_gpg_error (GPG_ERR_INV_ENGINE);
     446          58 :       end = tail;
     447             : 
     448         173 :       while (*end == ' ')
     449          57 :         end++;
     450             :       /* Skip the signature version.  */
     451          58 :       end = strchr (end, ' ');
     452          58 :       if (end)
     453             :         {
     454         173 :           while (*end == ' ')
     455          57 :             end++;
     456             : 
     457             :           /* Skip the reserved field.  */
     458          58 :           end = strchr (end, ' ');
     459          58 :           if (end)
     460             :             {
     461             :               /* Parse the pubkey algo.  */
     462          58 :               gpg_err_set_errno (0);
     463          57 :               sig->pubkey_algo = _gpgme_map_pk_algo (strtol (end, &tail, 0),
     464             :                                                      protocol);
     465          57 :               if (errno || end == tail || *tail != ' ')
     466           1 :                 return trace_gpg_error (GPG_ERR_INV_ENGINE);
     467          57 :               end = tail;
     468             : 
     469         172 :               while (*end == ' ')
     470          58 :                 end++;
     471             : 
     472          57 :               if (*end)
     473             :                 {
     474             :                   /* Parse the hash algo.  */
     475             : 
     476          57 :                   gpg_err_set_errno (0);
     477          57 :                   sig->hash_algo = strtol (end, &tail, 0);
     478          57 :                   if (errno || end == tail || *tail != ' ')
     479           0 :                     return trace_gpg_error (GPG_ERR_INV_ENGINE);
     480          58 :                   end = tail;
     481             :                 }
     482             :             }
     483             :         }
     484             :     }
     485          57 :   return 0;
     486             : }
     487             : 
     488             : 
     489             : static gpgme_error_t
     490         180 : parse_notation (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
     491             : {
     492             :   gpgme_error_t err;
     493         180 :   gpgme_sig_notation_t *lastp = &sig->notations;
     494         180 :   gpgme_sig_notation_t notation = sig->notations;
     495             :   char *p;
     496             : 
     497         180 :   if (code == GPGME_STATUS_NOTATION_NAME || code == GPGME_STATUS_POLICY_URL)
     498             :     {
     499          69 :       p = strchr (args, ' ');
     500          69 :       if (p)
     501           0 :         *p = '\0';
     502             : 
     503             :       /* FIXME: We could keep a pointer to the last notation in the list.  */
     504         207 :       while (notation && notation->value)
     505             :         {
     506          69 :           lastp = &notation->next;
     507          69 :           notation = notation->next;
     508             :         }
     509             : 
     510          69 :       if (notation)
     511             :         /* There is another notation name without data for the
     512             :            previous one.  The crypto backend misbehaves.  */
     513           0 :         return trace_gpg_error (GPG_ERR_INV_ENGINE);
     514             : 
     515          69 :       err = _gpgme_sig_notation_create (&notation, NULL, 0, NULL, 0, 0);
     516          69 :       if (err)
     517           0 :         return err;
     518             : 
     519          69 :       if (code == GPGME_STATUS_NOTATION_NAME)
     520             :         {
     521          46 :           err = _gpgme_decode_percent_string (args, &notation->name, 0, 0);
     522          47 :           if (err)
     523             :             {
     524           0 :               _gpgme_sig_notation_free (notation);
     525           0 :               return err;
     526             :             }
     527             : 
     528          47 :           notation->name_len = strlen (notation->name);
     529             : 
     530             :           /* Set default flags for use with older gpg versions which
     531             :            * do not emit a NOTATIONS_FLAG line.  */
     532          47 :           notation->flags = GPGME_SIG_NOTATION_HUMAN_READABLE;
     533          47 :           notation->human_readable = 1;
     534             :         }
     535             :       else
     536             :         {
     537             :           /* This is a policy URL.  */
     538             : 
     539          23 :           err = _gpgme_decode_percent_string (args, &notation->value, 0, 0);
     540          23 :           if (err)
     541             :             {
     542           0 :               _gpgme_sig_notation_free (notation);
     543           0 :               return err;
     544             :             }
     545             : 
     546          23 :           notation->value_len = strlen (notation->value);
     547             :         }
     548          70 :       *lastp = notation;
     549             :     }
     550         111 :   else if (code == GPGME_STATUS_NOTATION_FLAGS)
     551             :     {
     552             :       char *field[2];
     553             : 
     554         161 :       while (notation && notation->next)
     555             :         {
     556          69 :           lastp = &notation->next;
     557          69 :           notation = notation->next;
     558             :         }
     559             : 
     560          46 :       if (!notation || !notation->name)
     561             :         { /* There are notation flags without a previous notation name.
     562             :            * The crypto backend misbehaves.  */
     563           0 :           return trace_gpg_error (GPG_ERR_INV_ENGINE);
     564             :         }
     565          46 :       if (_gpgme_split_fields (args, field, DIM (field)) < 2)
     566             :         { /* Required args missing.  */
     567           0 :           return trace_gpg_error (GPG_ERR_INV_ENGINE);
     568             :         }
     569          45 :       notation->flags = 0;
     570          45 :       if (atoi (field[0]))
     571             :         {
     572           4 :           notation->flags |= GPGME_SIG_NOTATION_CRITICAL;
     573           4 :           notation->critical = 1;
     574             :         }
     575          46 :       if (atoi (field[1]))
     576             :         {
     577          45 :           notation->flags |= GPGME_SIG_NOTATION_HUMAN_READABLE;
     578          45 :           notation->human_readable = 1;
     579             :         }
     580             :     }
     581          65 :   else if (code == GPGME_STATUS_NOTATION_DATA)
     582             :     {
     583          65 :       int len = strlen (args) + 1;
     584             :       char *dest;
     585             : 
     586             :       /* FIXME: We could keep a pointer to the last notation in the list.  */
     587         237 :       while (notation && notation->next)
     588             :         {
     589         107 :           lastp = &notation->next;
     590         107 :           notation = notation->next;
     591             :         }
     592             : 
     593          65 :       if (!notation || !notation->name)
     594             :         /* There is notation data without a previous notation
     595             :            name.  The crypto backend misbehaves.  */
     596           0 :         return trace_gpg_error (GPG_ERR_INV_ENGINE);
     597             : 
     598          65 :       if (!notation->value)
     599             :         {
     600          46 :           dest = notation->value = malloc (len);
     601          46 :           if (!dest)
     602           0 :             return gpg_error_from_syserror ();
     603             :         }
     604             :       else
     605             :         {
     606          19 :           int cur_len = strlen (notation->value);
     607          19 :           dest = realloc (notation->value, len + strlen (notation->value));
     608          19 :           if (!dest)
     609           0 :             return gpg_error_from_syserror ();
     610          19 :           notation->value = dest;
     611          19 :           dest += cur_len;
     612             :         }
     613             : 
     614          65 :       err = _gpgme_decode_percent_string (args, &dest, len, 0);
     615          65 :       if (err)
     616           0 :         return err;
     617             : 
     618          65 :       notation->value_len += strlen (dest);
     619             :     }
     620             :   else
     621           0 :     return trace_gpg_error (GPG_ERR_INV_ENGINE);
     622         180 :   return 0;
     623             : }
     624             : 
     625             : 
     626             : static gpgme_error_t
     627          58 : parse_trust (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
     628             : {
     629          58 :   char *end = strchr (args, ' ');
     630             : 
     631          58 :   if (end)
     632          58 :     *end = '\0';
     633             : 
     634          58 :   switch (code)
     635             :     {
     636             :     case GPGME_STATUS_TRUST_UNDEFINED:
     637             :     default:
     638          20 :       sig->validity = GPGME_VALIDITY_UNKNOWN;
     639          20 :       break;
     640             : 
     641             :     case GPGME_STATUS_TRUST_NEVER:
     642           0 :       sig->validity = GPGME_VALIDITY_NEVER;
     643           0 :       break;
     644             : 
     645             :     case GPGME_STATUS_TRUST_MARGINAL:
     646          10 :       sig->validity = GPGME_VALIDITY_MARGINAL;
     647          10 :       break;
     648             : 
     649             :     case GPGME_STATUS_TRUST_FULLY:
     650             :     case GPGME_STATUS_TRUST_ULTIMATE:
     651          28 :       sig->validity = GPGME_VALIDITY_FULL;
     652          28 :       break;
     653             :     }
     654             : 
     655          58 :   sig->validity_reason = 0;
     656          58 :   sig->chain_model = 0;
     657          58 :   if (*args)
     658             :     {
     659          57 :       sig->validity_reason = atoi (args);
     660         172 :       while (*args && *args != ' ')
     661          58 :         args++;
     662          57 :       if (*args)
     663             :         {
     664           0 :           while (*args == ' ')
     665           0 :             args++;
     666           0 :           if (!strncmp (args, "chain", 2) && (args[2] == ' ' || !args[2]))
     667           0 :             sig->chain_model = 1;
     668             :         }
     669             :     }
     670             : 
     671          58 :   return 0;
     672             : }
     673             : 
     674             : 
     675             : /* Parse a TOFU_USER line and put the info into SIG.  */
     676             : static gpgme_error_t
     677          18 : parse_tofu_user (gpgme_signature_t sig, char *args, gpgme_protocol_t protocol)
     678             : {
     679             :   gpg_error_t err;
     680             :   char *tail;
     681             :   gpgme_user_id_t uid;
     682             :   gpgme_tofu_info_t ti;
     683          18 :   char *fpr = NULL;
     684          18 :   char *address = NULL;
     685             : 
     686          18 :   tail = strchr (args, ' ');
     687          18 :   if (!tail || tail == args)
     688             :     {
     689           0 :       err = trace_gpg_error (GPG_ERR_INV_ENGINE);  /* No fingerprint.  */
     690           0 :       goto leave;
     691             :     }
     692          18 :   *tail++ = 0;
     693             : 
     694          18 :   fpr = strdup (args);
     695          18 :   if (!fpr)
     696             :     {
     697           0 :       err = gpg_error_from_syserror ();
     698           0 :       goto leave;
     699             :     }
     700             : 
     701          18 :   if (sig->key && sig->key->fpr && strcmp (sig->key->fpr, fpr))
     702             :     {
     703             :       /* GnuPG since 2.1.17 emits multiple TOFU_USER lines with
     704             :          different fingerprints in case of conflicts for a signature. */
     705           1 :       err = gpg_error (GPG_ERR_DUP_VALUE);
     706           1 :       goto leave;
     707             :     }
     708             : 
     709          17 :   args = tail;
     710          17 :   tail = strchr (args, ' ');
     711          17 :   if (tail == args)
     712             :     {
     713           0 :       err = trace_gpg_error (GPG_ERR_INV_ENGINE);  /* No addr-spec.  */
     714           0 :       goto leave;
     715             :     }
     716          17 :   if (tail)
     717           0 :     *tail = 0;
     718             : 
     719          17 :   err = _gpgme_decode_percent_string (args, &address, 0, 0);
     720          17 :   if (err)
     721           0 :     goto leave;
     722             : 
     723          17 :   if (!sig->key)
     724             :     {
     725          11 :       err = _gpgme_key_new (&sig->key);
     726          11 :       if (err)
     727           0 :         goto leave;
     728          11 :       sig->key->fpr = fpr;
     729          11 :       sig->key->protocol = protocol;
     730          11 :       fpr = NULL;
     731             :     }
     732           6 :   else if (!sig->key->fpr)
     733             :     {
     734           0 :       err = trace_gpg_error (GPG_ERR_INTERNAL);
     735           0 :       goto leave;
     736             :     }
     737             : 
     738          17 :   err = _gpgme_key_append_name (sig->key, address, 0);
     739          17 :   if (err)
     740           0 :     goto leave;
     741             : 
     742          17 :   uid = sig->key->_last_uid;
     743          17 :   assert (uid);
     744             : 
     745          17 :   ti = calloc (1, sizeof *ti);
     746          17 :   if (!ti)
     747             :     {
     748           0 :       err = gpg_error_from_syserror ();
     749           0 :       goto leave;
     750             :     }
     751          17 :   uid->tofu = ti;
     752             : 
     753             : 
     754             :  leave:
     755          18 :   free (fpr);
     756          18 :   free (address);
     757          18 :   return err;
     758             : }
     759             : 
     760             : 
     761             : /* Parse a TOFU_STATS line and store it in the last tofu info of SIG.
     762             :  *
     763             :  *   TOFU_STATS <validity> <sign-count> <encr-count> \
     764             :  *                         [<policy> [<tm1> <tm2> <tm3> <tm4>]]
     765             :  */
     766             : static gpgme_error_t
     767          17 : parse_tofu_stats (gpgme_signature_t sig, char *args)
     768             : {
     769             :   gpgme_error_t err;
     770             :   gpgme_tofu_info_t ti;
     771             :   char *field[8];
     772             :   int nfields;
     773             :   unsigned long uval;
     774             : 
     775          17 :   if (!sig->key || !sig->key->_last_uid || !(ti = sig->key->_last_uid->tofu))
     776           0 :     return trace_gpg_error (GPG_ERR_INV_ENGINE); /* No TOFU_USER seen.  */
     777          17 :   if (ti->signfirst || ti->signcount || ti->validity || ti->policy)
     778           0 :     return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Already set.  */
     779             : 
     780          17 :   nfields = _gpgme_split_fields (args, field, DIM (field));
     781          17 :   if (nfields < 3)
     782           0 :     return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Required args missing.  */
     783             : 
     784             :   /* Note that we allow a value of up to 7 which is what we can store
     785             :    * in the ti->validity.  */
     786          17 :   err = _gpgme_strtoul_field (field[0], &uval);
     787          17 :   if (err || uval > 7)
     788           0 :     return trace_gpg_error (GPG_ERR_INV_ENGINE);
     789          17 :   ti->validity = uval;
     790             : 
     791             :   /* Parse the sign-count.  */
     792          17 :   err = _gpgme_strtoul_field (field[1], &uval);
     793          17 :   if (err)
     794           0 :     return trace_gpg_error (GPG_ERR_INV_ENGINE);
     795          17 :   if (uval > USHRT_MAX)
     796           0 :     uval = USHRT_MAX;
     797          17 :   ti->signcount = uval;
     798             : 
     799             :   /* Parse the encr-count.  */
     800          17 :   err = _gpgme_strtoul_field (field[2], &uval);
     801          17 :   if (err)
     802           0 :     return trace_gpg_error (GPG_ERR_INV_ENGINE);
     803          17 :   if (uval > USHRT_MAX)
     804           0 :     uval = USHRT_MAX;
     805          17 :   ti->encrcount = uval;
     806             : 
     807          17 :   if (nfields == 3)
     808           0 :     return 0; /* All mandatory fields parsed.  */
     809             : 
     810             :   /* Parse the policy.  */
     811          17 :   if (!strcmp (field[3], "none"))
     812           0 :     ti->policy = GPGME_TOFU_POLICY_NONE;
     813          17 :   else if (!strcmp (field[3], "auto"))
     814          16 :     ti->policy = GPGME_TOFU_POLICY_AUTO;
     815           1 :   else if (!strcmp (field[3], "good"))
     816           0 :     ti->policy = GPGME_TOFU_POLICY_GOOD;
     817           1 :   else if (!strcmp (field[3], "bad"))
     818           0 :     ti->policy = GPGME_TOFU_POLICY_BAD;
     819           1 :   else if (!strcmp (field[3], "ask"))
     820           1 :     ti->policy = GPGME_TOFU_POLICY_ASK;
     821             :   else /* "unknown" and invalid policy strings.  */
     822           0 :     ti->policy = GPGME_TOFU_POLICY_UNKNOWN;
     823             : 
     824          17 :   if (nfields == 4)
     825           0 :     return 0; /* No more optional fields.  */
     826             : 
     827             :   /* Parse first and last seen timestamps (none or both are required).  */
     828          17 :   if (nfields < 6)
     829           0 :     return trace_gpg_error (GPG_ERR_INV_ENGINE); /* "tm2" missing.  */
     830          17 :   err = _gpgme_strtoul_field (field[4], &uval);
     831          17 :   if (err)
     832           0 :     return trace_gpg_error (GPG_ERR_INV_ENGINE);
     833          17 :   ti->signfirst = uval;
     834          17 :   err = _gpgme_strtoul_field (field[5], &uval);
     835          17 :   if (err)
     836           0 :     return trace_gpg_error (GPG_ERR_INV_ENGINE);
     837          17 :   ti->signlast = uval;
     838          17 :   if (nfields > 7)
     839             :     {
     840             :       /* This condition is only to allow for gpg 2.1.15 - can
     841             :        * eventually be removed.  */
     842          17 :       err = _gpgme_strtoul_field (field[6], &uval);
     843          17 :       if (err)
     844           0 :         return trace_gpg_error (GPG_ERR_INV_ENGINE);
     845          17 :       ti->encrfirst = uval;
     846          17 :       err = _gpgme_strtoul_field (field[7], &uval);
     847          17 :       if (err)
     848           0 :         return trace_gpg_error (GPG_ERR_INV_ENGINE);
     849          17 :       ti->encrlast = uval;
     850             :     }
     851             : 
     852          17 :   return 0;
     853             : }
     854             : 
     855             : 
     856             : /* Parse a TOFU_STATS_LONG line and store it in the last tofu info of SIG.  */
     857             : static gpgme_error_t
     858          16 : parse_tofu_stats_long (gpgme_signature_t sig, char *args, int raw)
     859             : {
     860             :   gpgme_error_t err;
     861             :   gpgme_tofu_info_t ti;
     862             :   char *p;
     863             : 
     864          16 :   if (!sig->key || !sig->key->_last_uid || !(ti = sig->key->_last_uid->tofu))
     865           0 :     return trace_gpg_error (GPG_ERR_INV_ENGINE); /* No TOFU_USER seen.  */
     866          16 :   if (ti->description)
     867           0 :     return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Already set.  */
     868             : 
     869          16 :   err = _gpgme_decode_percent_string (args, &ti->description, 0, 0);
     870          16 :   if (err)
     871           0 :     return err;
     872             : 
     873             :   /* Remove the non-breaking spaces.  */
     874          16 :   if (!raw)
     875             :     {
     876        1373 :       for (p = ti->description; *p; p++)
     877        1357 :         if (*p == '~')
     878          32 :           *p = ' ';
     879             :     }
     880          16 :   return 0;
     881             : }
     882             : 
     883             : 
     884             : /* Parse an error status line and if SET_STATUS is true update the
     885             :    result status as appropriate.  With SET_STATUS being false, only
     886             :    check for an error.  */
     887             : static gpgme_error_t
     888           5 : parse_error (gpgme_signature_t sig, char *args, int set_status)
     889             : {
     890             :   gpgme_error_t err;
     891           5 :   char *where = strchr (args, ' ');
     892             :   char *which;
     893             : 
     894           5 :   if (where)
     895             :     {
     896           5 :       *where = '\0';
     897           5 :       which = where + 1;
     898             : 
     899           5 :       where = strchr (which, ' ');
     900           5 :       if (where)
     901           0 :         *where = '\0';
     902             : 
     903           5 :       where = args;
     904             :     }
     905             :   else
     906           0 :     return trace_gpg_error (GPG_ERR_INV_ENGINE);
     907             : 
     908           5 :   err = atoi (which);
     909             : 
     910           5 :   if (!strcmp (where, "proc_pkt.plaintext")
     911           5 :       && gpg_err_code (err) == GPG_ERR_BAD_DATA)
     912             :     {
     913             :       /* This indicates a double plaintext.  The only solid way to
     914             :          handle this is by failing the oepration.  */
     915           5 :       return gpg_error (GPG_ERR_BAD_DATA);
     916             :     }
     917           0 :   else if (!set_status)
     918             :     ;
     919           0 :   else if (!strcmp (where, "verify.findkey"))
     920           0 :     sig->status = err;
     921           0 :   else if (!strcmp (where, "verify.keyusage")
     922           0 :            && gpg_err_code (err) == GPG_ERR_WRONG_KEY_USAGE)
     923           0 :     sig->wrong_key_usage = 1;
     924             : 
     925           0 :   return 0;
     926             : }
     927             : 
     928             : 
     929             : gpgme_error_t
     930        1238 : _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
     931             : {
     932        1238 :   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
     933             :   gpgme_error_t err;
     934             :   void *hook;
     935             :   op_data_t opd;
     936             :   gpgme_signature_t sig;
     937             :   char *end;
     938             : 
     939        1238 :   err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook, -1, NULL);
     940        1239 :   opd = hook;
     941        1239 :   if (err)
     942           0 :     return err;
     943             : 
     944        1239 :   sig = opd->current_sig;
     945             : 
     946        1239 :   switch (code)
     947             :     {
     948             :     case GPGME_STATUS_NEWSIG:
     949          63 :       if (sig)
     950           1 :         calc_sig_summary (sig);
     951          63 :       err = prepare_new_sig (opd);
     952          64 :       opd->only_newsig_seen = 1;
     953          64 :       opd->conflict_user_seen = 0;
     954          64 :       return err;
     955             : 
     956             :     case GPGME_STATUS_GOODSIG:
     957             :     case GPGME_STATUS_EXPSIG:
     958             :     case GPGME_STATUS_EXPKEYSIG:
     959             :     case GPGME_STATUS_BADSIG:
     960             :     case GPGME_STATUS_ERRSIG:
     961             :     case GPGME_STATUS_REVKEYSIG:
     962          67 :       if (sig && !opd->did_prepare_new_sig)
     963           0 :         calc_sig_summary (sig);
     964          67 :       opd->only_newsig_seen = 0;
     965          67 :       return parse_new_sig (opd, code, args, ctx->protocol);
     966             : 
     967             :     case GPGME_STATUS_VALIDSIG:
     968          58 :       opd->only_newsig_seen = 0;
     969          58 :       return sig ? parse_valid_sig (sig, args, ctx->protocol)
     970         116 :         : trace_gpg_error (GPG_ERR_INV_ENGINE);
     971             : 
     972             :     case GPGME_STATUS_NODATA:
     973           3 :       opd->only_newsig_seen = 0;
     974           3 :       if (!sig)
     975           3 :         return gpg_error (GPG_ERR_NO_DATA);
     976           0 :       sig->status = gpg_error (GPG_ERR_NO_DATA);
     977           0 :       break;
     978             : 
     979             :     case GPGME_STATUS_UNEXPECTED:
     980           0 :       opd->only_newsig_seen = 0;
     981           0 :       if (!sig)
     982           0 :         return gpg_error (GPG_ERR_GENERAL);
     983           0 :       sig->status = gpg_error (GPG_ERR_NO_DATA);
     984           0 :       break;
     985             : 
     986             :     case GPGME_STATUS_NOTATION_NAME:
     987             :     case GPGME_STATUS_NOTATION_FLAGS:
     988             :     case GPGME_STATUS_NOTATION_DATA:
     989             :     case GPGME_STATUS_POLICY_URL:
     990         180 :       opd->only_newsig_seen = 0;
     991             :       return sig ? parse_notation (sig, code, args)
     992         180 :         : trace_gpg_error (GPG_ERR_INV_ENGINE);
     993             : 
     994             :     case GPGME_STATUS_TRUST_UNDEFINED:
     995             :     case GPGME_STATUS_TRUST_NEVER:
     996             :     case GPGME_STATUS_TRUST_MARGINAL:
     997             :     case GPGME_STATUS_TRUST_FULLY:
     998             :     case GPGME_STATUS_TRUST_ULTIMATE:
     999          58 :       opd->only_newsig_seen = 0;
    1000             :       return sig ? parse_trust (sig, code, args)
    1001          58 :         : trace_gpg_error (GPG_ERR_INV_ENGINE);
    1002             : 
    1003             :     case GPGME_STATUS_PKA_TRUST_BAD:
    1004             :     case GPGME_STATUS_PKA_TRUST_GOOD:
    1005           0 :       opd->only_newsig_seen = 0;
    1006             :       /* Check that we only get one of these status codes per
    1007             :          signature; if not the crypto backend misbehaves.  */
    1008           0 :       if (!sig || sig->pka_trust || sig->pka_address)
    1009           0 :         return trace_gpg_error (GPG_ERR_INV_ENGINE);
    1010           0 :       sig->pka_trust = code == GPGME_STATUS_PKA_TRUST_GOOD? 2 : 1;
    1011           0 :       end = strchr (args, ' ');
    1012           0 :       if (end)
    1013           0 :         *end = 0;
    1014           0 :       sig->pka_address = strdup (args);
    1015           0 :       break;
    1016             : 
    1017             :     case GPGME_STATUS_TOFU_USER:
    1018          18 :       opd->only_newsig_seen = 0;
    1019          18 :       if (!sig)
    1020           0 :         return trace_gpg_error (GPG_ERR_INV_ENGINE);
    1021          18 :       err = parse_tofu_user (sig, args, ctx->protocol);
    1022             :       /* gpg emits TOFU User lines for each conflicting key.
    1023             :        * GPGME does not expose this to have a clean API and
    1024             :        * a GPGME user can do a keylisting with the address
    1025             :        * normalisation.
    1026             :        * So when a duplicated TOFU_USER line is encountered
    1027             :        * we ignore the conflicting tofu stats emitted afterwards.
    1028             :        */
    1029          18 :       if (gpg_err_code (err) == GPG_ERR_DUP_VALUE)
    1030             :         {
    1031           1 :           opd->conflict_user_seen = 1;
    1032           1 :           break;
    1033             :         }
    1034          17 :       opd->conflict_user_seen = 0;
    1035          17 :       return trace_gpg_error (err);
    1036             : 
    1037             :     case GPGME_STATUS_TOFU_STATS:
    1038          18 :       opd->only_newsig_seen = 0;
    1039          18 :       if (opd->conflict_user_seen)
    1040           1 :         break;
    1041             :       return sig ? parse_tofu_stats (sig, args)
    1042          17 :         /*    */ : trace_gpg_error (GPG_ERR_INV_ENGINE);
    1043             : 
    1044             :     case GPGME_STATUS_TOFU_STATS_LONG:
    1045          16 :       opd->only_newsig_seen = 0;
    1046          16 :       if (opd->conflict_user_seen)
    1047           0 :         break;
    1048          16 :       return sig ? parse_tofu_stats_long (sig, args, ctx->raw_description)
    1049          32 :         /*    */ : trace_gpg_error (GPG_ERR_INV_ENGINE);
    1050             : 
    1051             :     case GPGME_STATUS_ERROR:
    1052           5 :       opd->only_newsig_seen = 0;
    1053             :       /* Some  error stati are informational, so we don't return an
    1054             :          error code if we are not ready to process this status.  */
    1055           5 :       return parse_error (sig, args, !!sig );
    1056             : 
    1057             :     case GPGME_STATUS_FAILURE:
    1058           5 :       opd->failure_code = _gpgme_parse_failure (args);
    1059           5 :       break;
    1060             : 
    1061             :     case GPGME_STATUS_EOF:
    1062          74 :       if (sig && !opd->did_prepare_new_sig)
    1063          67 :         calc_sig_summary (sig);
    1064          74 :       if (opd->only_newsig_seen && sig)
    1065             :         {
    1066             :           gpgme_signature_t sig2;
    1067             :           /* The last signature has no valid information - remove it
    1068             :              from the list. */
    1069           0 :           assert (!sig->next);
    1070           0 :           if (sig == opd->result.signatures)
    1071           0 :             opd->result.signatures = NULL;
    1072             :           else
    1073             :             {
    1074           0 :               for (sig2 = opd->result.signatures; sig2; sig2 = sig2->next)
    1075           0 :                 if (sig2->next == sig)
    1076             :                   {
    1077           0 :                     sig2->next = NULL;
    1078           0 :                     break;
    1079             :                   }
    1080             :             }
    1081             :           /* Note that there is no need to release the members of SIG
    1082             :              because we won't be here if they have been set. */
    1083           0 :           free (sig);
    1084           0 :           opd->current_sig = NULL;
    1085             :         }
    1086          74 :       opd->only_newsig_seen = 0;
    1087          74 :       if (opd->failure_code)
    1088           0 :         return opd->failure_code;
    1089          74 :       break;
    1090             : 
    1091             :     case GPGME_STATUS_PLAINTEXT:
    1092          49 :       if (++opd->plaintext_seen > 1)
    1093           0 :         return gpg_error (GPG_ERR_BAD_DATA);
    1094             :       {
    1095          49 :         int mime = 0;
    1096          49 :         err = _gpgme_parse_plaintext (args, &opd->result.file_name, &mime);
    1097          49 :         if (err)
    1098           0 :           return err;
    1099          49 :         opd->result.is_mime = !!mime;
    1100             :       }
    1101          49 :       break;
    1102             : 
    1103             :     case GPGME_STATUS_VERIFICATION_COMPLIANCE_MODE:
    1104           4 :       PARSE_COMPLIANCE_FLAGS (args, opd->current_sig);
    1105           4 :       break;
    1106             : 
    1107             :     default:
    1108         621 :       break;
    1109             :     }
    1110         755 :   return 0;
    1111             : }
    1112             : 
    1113             : 
    1114             : static gpgme_error_t
    1115         838 : verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
    1116             : {
    1117             :   gpgme_error_t err;
    1118             : 
    1119         838 :   err = _gpgme_progress_status_handler (priv, code, args);
    1120         835 :   if (!err)
    1121         835 :     err = _gpgme_verify_status_handler (priv, code, args);
    1122         831 :   return err;
    1123             : }
    1124             : 
    1125             : 
    1126             : gpgme_error_t
    1127          80 : _gpgme_op_verify_init_result (gpgme_ctx_t ctx)
    1128             : {
    1129             :   void *hook;
    1130             :   op_data_t opd;
    1131             : 
    1132          80 :   return _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook,
    1133             :                                 sizeof (*opd), release_op_data);
    1134             : }
    1135             : 
    1136             : 
    1137             : static gpgme_error_t
    1138          61 : verify_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t sig,
    1139             :               gpgme_data_t signed_text, gpgme_data_t plaintext)
    1140             : {
    1141             :   gpgme_error_t err;
    1142             : 
    1143          61 :   err = _gpgme_op_reset (ctx, synchronous);
    1144          61 :   if (err)
    1145           0 :     return err;
    1146             : 
    1147          61 :   err = _gpgme_op_verify_init_result (ctx);
    1148          61 :   if (err)
    1149           0 :     return err;
    1150             : 
    1151          61 :   _gpgme_engine_set_status_handler (ctx->engine, verify_status_handler, ctx);
    1152             : 
    1153          60 :   if (!sig)
    1154           0 :     return gpg_error (GPG_ERR_NO_DATA);
    1155             : 
    1156          60 :   return _gpgme_engine_op_verify (ctx->engine, sig, signed_text, plaintext,
    1157             :                                   ctx);
    1158             : }
    1159             : 
    1160             : 
    1161             : /* Decrypt ciphertext CIPHER and make a signature verification within
    1162             :    CTX and store the resulting plaintext in PLAIN.  */
    1163             : gpgme_error_t
    1164           3 : gpgme_op_verify_start (gpgme_ctx_t ctx, gpgme_data_t sig,
    1165             :                        gpgme_data_t signed_text, gpgme_data_t plaintext)
    1166             : {
    1167             :   gpg_error_t err;
    1168           3 :   TRACE_BEG3 (DEBUG_CTX, "gpgme_op_verify_start", ctx,
    1169             :               "sig=%p, signed_text=%p, plaintext=%p",
    1170             :               sig, signed_text, plaintext);
    1171             : 
    1172           3 :   if (!ctx)
    1173           0 :     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
    1174             : 
    1175           3 :   err = verify_start (ctx, 0, sig, signed_text, plaintext);
    1176           3 :   return TRACE_ERR (err);
    1177             : }
    1178             : 
    1179             : 
    1180             : /* Decrypt ciphertext CIPHER and make a signature verification within
    1181             :    CTX and store the resulting plaintext in PLAIN.  */
    1182             : gpgme_error_t
    1183          57 : gpgme_op_verify (gpgme_ctx_t ctx, gpgme_data_t sig, gpgme_data_t signed_text,
    1184             :                  gpgme_data_t plaintext)
    1185             : {
    1186             :   gpgme_error_t err;
    1187             : 
    1188          57 :   TRACE_BEG3 (DEBUG_CTX, "gpgme_op_verify", ctx,
    1189             :               "sig=%p, signed_text=%p, plaintext=%p",
    1190             :               sig, signed_text, plaintext);
    1191             : 
    1192          58 :   if (!ctx)
    1193           0 :     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
    1194             : 
    1195          58 :   err = verify_start (ctx, 1, sig, signed_text, plaintext);
    1196          58 :   if (!err)
    1197          58 :     err = _gpgme_wait_one (ctx);
    1198          59 :   return TRACE_ERR (err);
    1199             : }
    1200             : 
    1201             : 
    1202             : /* Compatibility interfaces.  */
    1203             : 
    1204             : /* Get the key used to create signature IDX in CTX and return it in
    1205             :    R_KEY.  */
    1206             : gpgme_error_t
    1207           0 : gpgme_get_sig_key (gpgme_ctx_t ctx, int idx, gpgme_key_t *r_key)
    1208             : {
    1209             :   gpgme_verify_result_t result;
    1210             :   gpgme_signature_t sig;
    1211             : 
    1212           0 :   if (!ctx)
    1213           0 :     return gpg_error (GPG_ERR_INV_VALUE);
    1214             : 
    1215           0 :   result = gpgme_op_verify_result (ctx);
    1216           0 :   sig = result->signatures;
    1217             : 
    1218           0 :   while (sig && idx)
    1219             :     {
    1220           0 :       sig = sig->next;
    1221           0 :       idx--;
    1222             :     }
    1223           0 :   if (!sig || idx)
    1224           0 :     return gpg_error (GPG_ERR_EOF);
    1225             : 
    1226           0 :   return gpgme_get_key (ctx, sig->fpr, r_key, 0);
    1227             : }
    1228             : 
    1229             : 
    1230             : /* Retrieve the signature status of signature IDX in CTX after a
    1231             :    successful verify operation in R_STAT (if non-null).  The creation
    1232             :    time stamp of the signature is returned in R_CREATED (if non-null).
    1233             :    The function returns a string containing the fingerprint.  */
    1234             : const char *
    1235           0 : gpgme_get_sig_status (gpgme_ctx_t ctx, int idx,
    1236             :                       _gpgme_sig_stat_t *r_stat, time_t *r_created)
    1237             : {
    1238             :   gpgme_verify_result_t result;
    1239             :   gpgme_signature_t sig;
    1240             : 
    1241           0 :   result = gpgme_op_verify_result (ctx);
    1242           0 :   sig = result->signatures;
    1243             : 
    1244           0 :   while (sig && idx)
    1245             :     {
    1246           0 :       sig = sig->next;
    1247           0 :       idx--;
    1248             :     }
    1249           0 :   if (!sig || idx)
    1250           0 :     return NULL;
    1251             : 
    1252           0 :   if (r_stat)
    1253             :     {
    1254           0 :       switch (gpg_err_code (sig->status))
    1255             :         {
    1256             :         case GPG_ERR_NO_ERROR:
    1257           0 :           *r_stat = GPGME_SIG_STAT_GOOD;
    1258           0 :           break;
    1259             : 
    1260             :         case GPG_ERR_BAD_SIGNATURE:
    1261           0 :           *r_stat = GPGME_SIG_STAT_BAD;
    1262           0 :           break;
    1263             : 
    1264             :         case GPG_ERR_NO_PUBKEY:
    1265           0 :           *r_stat = GPGME_SIG_STAT_NOKEY;
    1266           0 :           break;
    1267             : 
    1268             :         case GPG_ERR_NO_DATA:
    1269           0 :           *r_stat = GPGME_SIG_STAT_NOSIG;
    1270           0 :           break;
    1271             : 
    1272             :         case GPG_ERR_SIG_EXPIRED:
    1273           0 :           *r_stat = GPGME_SIG_STAT_GOOD_EXP;
    1274           0 :           break;
    1275             : 
    1276             :         case GPG_ERR_KEY_EXPIRED:
    1277           0 :           *r_stat = GPGME_SIG_STAT_GOOD_EXPKEY;
    1278           0 :           break;
    1279             : 
    1280             :         default:
    1281           0 :           *r_stat = GPGME_SIG_STAT_ERROR;
    1282           0 :           break;
    1283             :         }
    1284             :     }
    1285           0 :   if (r_created)
    1286           0 :     *r_created = sig->timestamp;
    1287           0 :   return sig->fpr;
    1288             : }
    1289             : 
    1290             : 
    1291             : /* Retrieve certain attributes of a signature.  IDX is the index
    1292             :    number of the signature after a successful verify operation.  WHAT
    1293             :    is an attribute where GPGME_ATTR_EXPIRE is probably the most useful
    1294             :    one.  WHATIDX is to be passed as 0 for most attributes . */
    1295             : unsigned long
    1296           0 : gpgme_get_sig_ulong_attr (gpgme_ctx_t ctx, int idx,
    1297             :                           _gpgme_attr_t what, int whatidx)
    1298             : {
    1299             :   gpgme_verify_result_t result;
    1300             :   gpgme_signature_t sig;
    1301             : 
    1302             :   (void)whatidx;
    1303             : 
    1304           0 :   result = gpgme_op_verify_result (ctx);
    1305           0 :   sig = result->signatures;
    1306             : 
    1307           0 :   while (sig && idx)
    1308             :     {
    1309           0 :       sig = sig->next;
    1310           0 :       idx--;
    1311             :     }
    1312           0 :   if (!sig || idx)
    1313           0 :     return 0;
    1314             : 
    1315           0 :   switch (what)
    1316             :     {
    1317             :     case GPGME_ATTR_CREATED:
    1318           0 :       return sig->timestamp;
    1319             : 
    1320             :     case GPGME_ATTR_EXPIRE:
    1321           0 :       return sig->exp_timestamp;
    1322             : 
    1323             :     case GPGME_ATTR_VALIDITY:
    1324           0 :       return (unsigned long) sig->validity;
    1325             : 
    1326             :     case GPGME_ATTR_SIG_STATUS:
    1327           0 :       switch (gpg_err_code (sig->status))
    1328             :         {
    1329             :         case GPG_ERR_NO_ERROR:
    1330           0 :           return GPGME_SIG_STAT_GOOD;
    1331             : 
    1332             :         case GPG_ERR_BAD_SIGNATURE:
    1333           0 :           return GPGME_SIG_STAT_BAD;
    1334             : 
    1335             :         case GPG_ERR_NO_PUBKEY:
    1336           0 :           return GPGME_SIG_STAT_NOKEY;
    1337             : 
    1338             :         case GPG_ERR_NO_DATA:
    1339           0 :           return GPGME_SIG_STAT_NOSIG;
    1340             : 
    1341             :         case GPG_ERR_SIG_EXPIRED:
    1342           0 :           return GPGME_SIG_STAT_GOOD_EXP;
    1343             : 
    1344             :         case GPG_ERR_KEY_EXPIRED:
    1345           0 :           return GPGME_SIG_STAT_GOOD_EXPKEY;
    1346             : 
    1347             :         default:
    1348           0 :           return GPGME_SIG_STAT_ERROR;
    1349             :         }
    1350             : 
    1351             :     case GPGME_ATTR_SIG_SUMMARY:
    1352           0 :       return sig->summary;
    1353             : 
    1354             :     default:
    1355           0 :       break;
    1356             :     }
    1357           0 :   return 0;
    1358             : }
    1359             : 
    1360             : 
    1361             : const char *
    1362           0 : gpgme_get_sig_string_attr (gpgme_ctx_t ctx, int idx,
    1363             :                            _gpgme_attr_t what, int whatidx)
    1364             : {
    1365             :   gpgme_verify_result_t result;
    1366             :   gpgme_signature_t sig;
    1367             : 
    1368           0 :   result = gpgme_op_verify_result (ctx);
    1369           0 :   sig = result->signatures;
    1370             : 
    1371           0 :   while (sig && idx)
    1372             :     {
    1373           0 :       sig = sig->next;
    1374           0 :       idx--;
    1375             :     }
    1376           0 :   if (!sig || idx)
    1377           0 :     return NULL;
    1378             : 
    1379           0 :   switch (what)
    1380             :     {
    1381             :     case GPGME_ATTR_FPR:
    1382           0 :       return sig->fpr;
    1383             : 
    1384             :     case GPGME_ATTR_ERRTOK:
    1385           0 :       if (whatidx == 1)
    1386           0 :         return sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
    1387             :       else
    1388           0 :         return "";
    1389             :     default:
    1390           0 :       break;
    1391             :     }
    1392             : 
    1393           0 :   return NULL;
    1394             : }

Generated by: LCOV version 1.13