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

Generated by: LCOV version 1.13