84487ee4caed1899a936aed8fc258c4e1dd476d1
[gpgme.git] / src / verify.c
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
30 #include "gpgme.h"
31 #include "debug.h"
32 #include "util.h"
33 #include "context.h"
34 #include "ops.h"
35
36 \f
37 typedef struct
38 {
39   struct _gpgme_op_verify_result result;
40
41   gpgme_signature_t current_sig;
42   int did_prepare_new_sig;
43   int only_newsig_seen;
44   int plaintext_seen;
45 } *op_data_t;
46
47
48 static void
49 release_op_data (void *hook)
50 {
51   op_data_t opd = (op_data_t) hook;
52   gpgme_signature_t sig = opd->result.signatures;
53
54   while (sig)
55     {
56       gpgme_signature_t next = sig->next;
57       gpgme_sig_notation_t notation = sig->notations;
58
59       while (notation)
60         {
61           gpgme_sig_notation_t next_nota = notation->next;
62
63           _gpgme_sig_notation_free (notation);
64           notation = next_nota;
65         }
66
67       if (sig->fpr)
68         free (sig->fpr);
69       if (sig->pka_address)
70         free (sig->pka_address);
71       free (sig);
72       sig = next;
73     }
74
75   if (opd->result.file_name)
76     free (opd->result.file_name);
77 }
78
79
80 gpgme_verify_result_t
81 gpgme_op_verify_result (gpgme_ctx_t ctx)
82 {
83   void *hook;
84   op_data_t opd;
85   gpgme_error_t err;
86   gpgme_signature_t sig;
87
88   TRACE_BEG (DEBUG_CTX, "gpgme_op_verify_result", ctx);
89   err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook, -1, NULL);
90   opd = hook;
91   if (err || !opd)
92     {
93       TRACE_SUC0 ("result=(null)");
94       return NULL;
95     }
96
97   /* It is possible that we saw a new signature only followed by an
98      ERROR line for that.  In particular a missing X.509 key triggers
99      this.  In this case it is surprising that the summary field has
100      not been updated.  We fix it here by explicitly looking for this
101      case.  The real fix would be to have GPGME emit ERRSIG.  */
102   for (sig = opd->result.signatures; sig; sig = sig->next)
103     {
104       if (!sig->summary)
105         {
106           switch (gpg_err_code (sig->status))
107             {
108             case GPG_ERR_KEY_EXPIRED:
109               sig->summary |= GPGME_SIGSUM_KEY_EXPIRED;
110               break;
111
112             case GPG_ERR_NO_PUBKEY:
113               sig->summary |= GPGME_SIGSUM_KEY_MISSING;
114               break;
115
116             default:
117               break;
118             }
119         }
120     }
121
122   /* Now for some tracing stuff. */
123   if (_gpgme_debug_trace ())
124     {
125       int i;
126
127       for (sig = opd->result.signatures, i = 0; sig; sig = sig->next, i++)
128         {
129           TRACE_LOG4 ("sig[%i] = fpr %s, summary 0x%x, status %s",
130                       i, sig->fpr, sig->summary, gpg_strerror (sig->status));
131           TRACE_LOG6 ("sig[%i] = timestamps 0x%x/0x%x flags:%s%s%s",
132                       i, sig->timestamp, sig->exp_timestamp,
133                       sig->wrong_key_usage ? "wrong key usage" : "",
134                       sig->pka_trust == 1 ? "pka bad"
135                       : (sig->pka_trust == 2 ? "pka_okay" : "pka RFU"),
136                       sig->chain_model ? "chain model" : "");
137           TRACE_LOG5 ("sig[%i] = validity 0x%x (%s), algos %s/%s",
138                       i, sig->validity, gpg_strerror (sig->validity_reason),
139                       gpgme_pubkey_algo_name (sig->pubkey_algo),
140                       gpgme_hash_algo_name (sig->hash_algo));
141           if (sig->pka_address)
142             {
143               TRACE_LOG2 ("sig[%i] = PKA address %s", i, sig->pka_address);
144             }
145           if (sig->notations)
146             {
147               TRACE_LOG1 ("sig[%i] = has notations (not shown)", i);
148             }
149         }
150     }
151
152   TRACE_SUC1 ("result=%p", &opd->result);
153   return &opd->result;
154 }
155
156 \f
157 /* Build a summary vector from RESULT. */
158 static void
159 calc_sig_summary (gpgme_signature_t sig)
160 {
161   unsigned long sum = 0;
162
163   /* Calculate the red/green flag.  */
164   if (sig->validity == GPGME_VALIDITY_FULL
165       || sig->validity == GPGME_VALIDITY_ULTIMATE)
166     {
167       if (gpg_err_code (sig->status) == GPG_ERR_NO_ERROR
168           || gpg_err_code (sig->status) == GPG_ERR_SIG_EXPIRED
169           || gpg_err_code (sig->status) == GPG_ERR_KEY_EXPIRED)
170         sum |= GPGME_SIGSUM_GREEN;
171     }
172   else if (sig->validity == GPGME_VALIDITY_NEVER)
173     {
174       if (gpg_err_code (sig->status) == GPG_ERR_NO_ERROR
175           || gpg_err_code (sig->status) == GPG_ERR_SIG_EXPIRED
176           || gpg_err_code (sig->status) == GPG_ERR_KEY_EXPIRED)
177         sum |= GPGME_SIGSUM_RED;
178     }
179   else if (gpg_err_code (sig->status) == GPG_ERR_BAD_SIGNATURE)
180     sum |= GPGME_SIGSUM_RED;
181
182
183   /* FIXME: handle the case when key and message are expired. */
184   switch (gpg_err_code (sig->status))
185     {
186     case GPG_ERR_SIG_EXPIRED:
187       sum |= GPGME_SIGSUM_SIG_EXPIRED;
188       break;
189
190     case GPG_ERR_KEY_EXPIRED:
191       sum |= GPGME_SIGSUM_KEY_EXPIRED;
192       break;
193
194     case GPG_ERR_NO_PUBKEY:
195       sum |= GPGME_SIGSUM_KEY_MISSING;
196       break;
197
198     case GPG_ERR_CERT_REVOKED:
199       sum |= GPGME_SIGSUM_KEY_REVOKED;
200       break;
201
202     case GPG_ERR_BAD_SIGNATURE:
203     case GPG_ERR_NO_ERROR:
204       break;
205
206     default:
207       sum |= GPGME_SIGSUM_SYS_ERROR;
208       break;
209     }
210
211   /* Now look at the certain reason codes.  */
212   switch (gpg_err_code (sig->validity_reason))
213     {
214     case GPG_ERR_CRL_TOO_OLD:
215       if (sig->validity == GPGME_VALIDITY_UNKNOWN)
216         sum |= GPGME_SIGSUM_CRL_TOO_OLD;
217       break;
218
219     case GPG_ERR_CERT_REVOKED:
220       /* Note that this is a second way to set this flag.  It may also
221          have been set due to a sig->status of STATUS_REVKEYSIG from
222          parse_new_sig.  */
223       sum |= GPGME_SIGSUM_KEY_REVOKED;
224       break;
225
226     default:
227       break;
228     }
229
230   /* Check other flags. */
231   if (sig->wrong_key_usage)
232     sum |= GPGME_SIGSUM_BAD_POLICY;
233
234   /* Set the valid flag when the signature is unquestionable
235      valid.  (The test is identical to if(sum == GPGME_SIGSUM_GREEN)). */
236   if ((sum & GPGME_SIGSUM_GREEN) && !(sum & ~GPGME_SIGSUM_GREEN))
237     sum |= GPGME_SIGSUM_VALID;
238
239   sig->summary = sum;
240 }
241
242
243 static gpgme_error_t
244 prepare_new_sig (op_data_t opd)
245 {
246   gpgme_signature_t sig;
247
248   if (opd->only_newsig_seen && opd->current_sig)
249     {
250       /* We have only seen the NEWSIG status and nothing else - we
251          better skip this signature therefore and reuse it for the
252          next possible signature. */
253       sig = opd->current_sig;
254       memset (sig, 0, sizeof *sig);
255       assert (opd->result.signatures == sig);
256     }
257   else
258     {
259       sig = calloc (1, sizeof (*sig));
260       if (!sig)
261         return gpg_error_from_syserror ();
262       if (!opd->result.signatures)
263         opd->result.signatures = sig;
264       if (opd->current_sig)
265         opd->current_sig->next = sig;
266       opd->current_sig = sig;
267     }
268   opd->did_prepare_new_sig = 1;
269   opd->only_newsig_seen = 0;
270   return 0;
271 }
272
273 static gpgme_error_t
274 parse_new_sig (op_data_t opd, gpgme_status_code_t code, char *args,
275                gpgme_protocol_t protocol)
276 {
277   gpgme_signature_t sig;
278   char *end = strchr (args, ' ');
279   char *tail;
280
281   if (end)
282     {
283       *end = '\0';
284       end++;
285     }
286
287   if (!opd->did_prepare_new_sig)
288     {
289       gpg_error_t err;
290
291       err = prepare_new_sig (opd);
292       if (err)
293         return err;
294     }
295   assert (opd->did_prepare_new_sig);
296   opd->did_prepare_new_sig = 0;
297
298   assert (opd->current_sig);
299   sig = opd->current_sig;
300
301   /* FIXME: We should set the source of the state.  */
302   switch (code)
303     {
304     case GPGME_STATUS_GOODSIG:
305       sig->status = gpg_error (GPG_ERR_NO_ERROR);
306       break;
307
308     case GPGME_STATUS_EXPSIG:
309       sig->status = gpg_error (GPG_ERR_SIG_EXPIRED);
310       break;
311
312     case GPGME_STATUS_EXPKEYSIG:
313       sig->status = gpg_error (GPG_ERR_KEY_EXPIRED);
314       break;
315
316     case GPGME_STATUS_BADSIG:
317       sig->status = gpg_error (GPG_ERR_BAD_SIGNATURE);
318       break;
319
320     case GPGME_STATUS_REVKEYSIG:
321       sig->status = gpg_error (GPG_ERR_CERT_REVOKED);
322       break;
323
324     case GPGME_STATUS_ERRSIG:
325       /* Parse the pubkey algo.  */
326       if (!end)
327         goto parse_err_sig_fail;
328       gpg_err_set_errno (0);
329       sig->pubkey_algo = _gpgme_map_pk_algo (strtol (end, &tail, 0), protocol);
330       if (errno || end == tail || *tail != ' ')
331         goto parse_err_sig_fail;
332       end = tail;
333       while (*end == ' ')
334         end++;
335
336       /* Parse the hash algo.  */
337       if (!*end)
338         goto parse_err_sig_fail;
339       gpg_err_set_errno (0);
340       sig->hash_algo = strtol (end, &tail, 0);
341       if (errno || end == tail || *tail != ' ')
342         goto parse_err_sig_fail;
343       end = tail;
344       while (*end == ' ')
345         end++;
346
347       /* Skip the sig class.  */
348       end = strchr (end, ' ');
349       if (!end)
350         goto parse_err_sig_fail;
351       while (*end == ' ')
352         end++;
353
354       /* Parse the timestamp.  */
355       sig->timestamp = _gpgme_parse_timestamp (end, &tail);
356       if (sig->timestamp == -1 || end == tail || (*tail && *tail != ' '))
357         return trace_gpg_error (GPG_ERR_INV_ENGINE);
358       end = tail;
359       while (*end == ' ')
360         end++;
361
362       /* Parse the return code.  */
363       if (end[0] && (!end[1] || end[1] == ' '))
364         {
365           switch (end[0])
366             {
367             case '4':
368               sig->status = gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
369               break;
370
371             case '9':
372               sig->status = gpg_error (GPG_ERR_NO_PUBKEY);
373               break;
374
375             default:
376               sig->status = gpg_error (GPG_ERR_GENERAL);
377             }
378         }
379       else
380         goto parse_err_sig_fail;
381
382       goto parse_err_sig_ok;
383
384     parse_err_sig_fail:
385       sig->status = gpg_error (GPG_ERR_GENERAL);
386     parse_err_sig_ok:
387       break;
388
389     default:
390       return gpg_error (GPG_ERR_GENERAL);
391     }
392
393   if (*args)
394     {
395       sig->fpr = strdup (args);
396       if (!sig->fpr)
397         return gpg_error_from_syserror ();
398     }
399   return 0;
400 }
401
402
403 static gpgme_error_t
404 parse_valid_sig (gpgme_signature_t sig, char *args, gpgme_protocol_t protocol)
405 {
406   char *end = strchr (args, ' ');
407   if (end)
408     {
409       *end = '\0';
410       end++;
411     }
412
413   if (!*args)
414     /* We require at least the fingerprint.  */
415     return gpg_error (GPG_ERR_GENERAL);
416
417   if (sig->fpr)
418     free (sig->fpr);
419   sig->fpr = strdup (args);
420   if (!sig->fpr)
421     return gpg_error_from_syserror ();
422
423   /* Skip the creation date.  */
424   end = strchr (end, ' ');
425   if (end)
426     {
427       char *tail;
428
429       sig->timestamp = _gpgme_parse_timestamp (end, &tail);
430       if (sig->timestamp == -1 || end == tail || (*tail && *tail != ' '))
431         return trace_gpg_error (GPG_ERR_INV_ENGINE);
432       end = tail;
433
434       sig->exp_timestamp = _gpgme_parse_timestamp (end, &tail);
435       if (sig->exp_timestamp == -1 || end == tail || (*tail && *tail != ' '))
436         return trace_gpg_error (GPG_ERR_INV_ENGINE);
437       end = tail;
438
439       while (*end == ' ')
440         end++;
441       /* Skip the signature version.  */
442       end = strchr (end, ' ');
443       if (end)
444         {
445           while (*end == ' ')
446             end++;
447
448           /* Skip the reserved field.  */
449           end = strchr (end, ' ');
450           if (end)
451             {
452               /* Parse the pubkey algo.  */
453               gpg_err_set_errno (0);
454               sig->pubkey_algo = _gpgme_map_pk_algo (strtol (end, &tail, 0),
455                                                      protocol);
456               if (errno || end == tail || *tail != ' ')
457                 return trace_gpg_error (GPG_ERR_INV_ENGINE);
458               end = tail;
459
460               while (*end == ' ')
461                 end++;
462
463               if (*end)
464                 {
465                   /* Parse the hash algo.  */
466
467                   gpg_err_set_errno (0);
468                   sig->hash_algo = strtol (end, &tail, 0);
469                   if (errno || end == tail || *tail != ' ')
470                     return trace_gpg_error (GPG_ERR_INV_ENGINE);
471                   end = tail;
472                 }
473             }
474         }
475     }
476   return 0;
477 }
478
479
480 static gpgme_error_t
481 parse_notation (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
482 {
483   gpgme_error_t err;
484   gpgme_sig_notation_t *lastp = &sig->notations;
485   gpgme_sig_notation_t notation = sig->notations;
486   char *end = strchr (args, ' ');
487
488   if (end)
489     *end = '\0';
490
491   if (code == GPGME_STATUS_NOTATION_NAME || code == GPGME_STATUS_POLICY_URL)
492     {
493       /* FIXME: We could keep a pointer to the last notation in the list.  */
494       while (notation && notation->value)
495         {
496           lastp = &notation->next;
497           notation = notation->next;
498         }
499
500       if (notation)
501         /* There is another notation name without data for the
502            previous one.  The crypto backend misbehaves.  */
503         return trace_gpg_error (GPG_ERR_INV_ENGINE);
504
505       err = _gpgme_sig_notation_create (&notation, NULL, 0, NULL, 0, 0);
506       if (err)
507         return err;
508
509       if (code == GPGME_STATUS_NOTATION_NAME)
510         {
511           err = _gpgme_decode_percent_string (args, &notation->name, 0, 0);
512           if (err)
513             {
514               _gpgme_sig_notation_free (notation);
515               return err;
516             }
517
518           notation->name_len = strlen (notation->name);
519
520           /* FIXME: For now we fake the human-readable flag.  The
521              critical flag can not be reported as it is not
522              provided.  */
523           notation->flags = GPGME_SIG_NOTATION_HUMAN_READABLE;
524           notation->human_readable = 1;
525         }
526       else
527         {
528           /* This is a policy URL.  */
529
530           err = _gpgme_decode_percent_string (args, &notation->value, 0, 0);
531           if (err)
532             {
533               _gpgme_sig_notation_free (notation);
534               return err;
535             }
536
537           notation->value_len = strlen (notation->value);
538         }
539       *lastp = notation;
540     }
541   else if (code == GPGME_STATUS_NOTATION_DATA)
542     {
543       int len = strlen (args) + 1;
544       char *dest;
545
546       /* FIXME: We could keep a pointer to the last notation in the list.  */
547       while (notation && notation->next)
548         {
549           lastp = &notation->next;
550           notation = notation->next;
551         }
552
553       if (!notation || !notation->name)
554         /* There is notation data without a previous notation
555            name.  The crypto backend misbehaves.  */
556         return trace_gpg_error (GPG_ERR_INV_ENGINE);
557
558       if (!notation->value)
559         {
560           dest = notation->value = malloc (len);
561           if (!dest)
562             return gpg_error_from_syserror ();
563         }
564       else
565         {
566           int cur_len = strlen (notation->value);
567           dest = realloc (notation->value, len + strlen (notation->value));
568           if (!dest)
569             return gpg_error_from_syserror ();
570           notation->value = dest;
571           dest += cur_len;
572         }
573
574       err = _gpgme_decode_percent_string (args, &dest, len, 0);
575       if (err)
576         return err;
577
578       notation->value_len += strlen (dest);
579     }
580   else
581     return trace_gpg_error (GPG_ERR_INV_ENGINE);
582   return 0;
583 }
584
585
586 static gpgme_error_t
587 parse_trust (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
588 {
589   char *end = strchr (args, ' ');
590
591   if (end)
592     *end = '\0';
593
594   switch (code)
595     {
596     case GPGME_STATUS_TRUST_UNDEFINED:
597     default:
598       sig->validity = GPGME_VALIDITY_UNKNOWN;
599       break;
600
601     case GPGME_STATUS_TRUST_NEVER:
602       sig->validity = GPGME_VALIDITY_NEVER;
603       break;
604
605     case GPGME_STATUS_TRUST_MARGINAL:
606       sig->validity = GPGME_VALIDITY_MARGINAL;
607       break;
608
609     case GPGME_STATUS_TRUST_FULLY:
610     case GPGME_STATUS_TRUST_ULTIMATE:
611       sig->validity = GPGME_VALIDITY_FULL;
612       break;
613     }
614
615   sig->validity_reason = 0;
616   sig->chain_model = 0;
617   if (*args)
618     {
619       sig->validity_reason = atoi (args);
620       while (*args && *args != ' ')
621         args++;
622       if (*args)
623         {
624           while (*args == ' ')
625             args++;
626           if (!strncmp (args, "chain", 2) && (args[2] == ' ' || !args[2]))
627             sig->chain_model = 1;
628         }
629     }
630
631   return 0;
632 }
633
634
635 /* Parse an error status line and if SET_STATUS is true update the
636    result status as appropriate.  With SET_STATUS being false, only
637    check for an error.  */
638 static gpgme_error_t
639 parse_error (gpgme_signature_t sig, char *args, int set_status)
640 {
641   gpgme_error_t err;
642   char *where = strchr (args, ' ');
643   char *which;
644
645   if (where)
646     {
647       *where = '\0';
648       which = where + 1;
649
650       where = strchr (which, ' ');
651       if (where)
652         *where = '\0';
653
654       where = args;
655     }
656   else
657     return trace_gpg_error (GPG_ERR_INV_ENGINE);
658
659   err = atoi (which);
660
661   if (!strcmp (where, "proc_pkt.plaintext")
662       && gpg_err_code (err) == GPG_ERR_BAD_DATA)
663     {
664       /* This indicates a double plaintext.  The only solid way to
665          handle this is by failing the oepration.  */
666       return gpg_error (GPG_ERR_BAD_DATA);
667     }
668   else if (!set_status)
669     ;
670   else if (!strcmp (where, "verify.findkey"))
671     sig->status = err;
672   else if (!strcmp (where, "verify.keyusage")
673            && gpg_err_code (err) == GPG_ERR_WRONG_KEY_USAGE)
674     sig->wrong_key_usage = 1;
675
676   return 0;
677 }
678
679
680 gpgme_error_t
681 _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
682 {
683   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
684   gpgme_error_t err;
685   void *hook;
686   op_data_t opd;
687   gpgme_signature_t sig;
688   char *end;
689
690   err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook, -1, NULL);
691   opd = hook;
692   if (err)
693     return err;
694
695   sig = opd->current_sig;
696
697   switch (code)
698     {
699     case GPGME_STATUS_NEWSIG:
700       if (sig)
701         calc_sig_summary (sig);
702       err = prepare_new_sig (opd);
703       opd->only_newsig_seen = 1;
704       return err;
705
706     case GPGME_STATUS_GOODSIG:
707     case GPGME_STATUS_EXPSIG:
708     case GPGME_STATUS_EXPKEYSIG:
709     case GPGME_STATUS_BADSIG:
710     case GPGME_STATUS_ERRSIG:
711     case GPGME_STATUS_REVKEYSIG:
712       if (sig && !opd->did_prepare_new_sig)
713         calc_sig_summary (sig);
714       opd->only_newsig_seen = 0;
715       return parse_new_sig (opd, code, args, ctx->protocol);
716
717     case GPGME_STATUS_VALIDSIG:
718       opd->only_newsig_seen = 0;
719       return sig ? parse_valid_sig (sig, args, ctx->protocol)
720         : trace_gpg_error (GPG_ERR_INV_ENGINE);
721
722     case GPGME_STATUS_NODATA:
723       opd->only_newsig_seen = 0;
724       if (!sig)
725         return gpg_error (GPG_ERR_NO_DATA);
726       sig->status = gpg_error (GPG_ERR_NO_DATA);
727       break;
728
729     case GPGME_STATUS_UNEXPECTED:
730       opd->only_newsig_seen = 0;
731       if (!sig)
732         return gpg_error (GPG_ERR_GENERAL);
733       sig->status = gpg_error (GPG_ERR_NO_DATA);
734       break;
735
736     case GPGME_STATUS_NOTATION_NAME:
737     case GPGME_STATUS_NOTATION_DATA:
738     case GPGME_STATUS_POLICY_URL:
739       opd->only_newsig_seen = 0;
740       return sig ? parse_notation (sig, code, args)
741         : trace_gpg_error (GPG_ERR_INV_ENGINE);
742
743     case GPGME_STATUS_TRUST_UNDEFINED:
744     case GPGME_STATUS_TRUST_NEVER:
745     case GPGME_STATUS_TRUST_MARGINAL:
746     case GPGME_STATUS_TRUST_FULLY:
747     case GPGME_STATUS_TRUST_ULTIMATE:
748       opd->only_newsig_seen = 0;
749       return sig ? parse_trust (sig, code, args)
750         : trace_gpg_error (GPG_ERR_INV_ENGINE);
751
752     case GPGME_STATUS_PKA_TRUST_BAD:
753     case GPGME_STATUS_PKA_TRUST_GOOD:
754       opd->only_newsig_seen = 0;
755       /* Check that we only get one of these status codes per
756          signature; if not the crypto backend misbehaves.  */
757       if (!sig || sig->pka_trust || sig->pka_address)
758         return trace_gpg_error (GPG_ERR_INV_ENGINE);
759       sig->pka_trust = code == GPGME_STATUS_PKA_TRUST_GOOD? 2 : 1;
760       end = strchr (args, ' ');
761       if (end)
762         *end = 0;
763       sig->pka_address = strdup (args);
764       break;
765
766     case GPGME_STATUS_ERROR:
767       opd->only_newsig_seen = 0;
768       /* Some  error stati are informational, so we don't return an
769          error code if we are not ready to process this status.  */
770       return parse_error (sig, args, !!sig );
771
772     case GPGME_STATUS_EOF:
773       if (sig && !opd->did_prepare_new_sig)
774         calc_sig_summary (sig);
775       if (opd->only_newsig_seen && sig)
776         {
777           gpgme_signature_t sig2;
778           /* The last signature has no valid information - remove it
779              from the list. */
780           assert (!sig->next);
781           if (sig == opd->result.signatures)
782             opd->result.signatures = NULL;
783           else
784             {
785               for (sig2 = opd->result.signatures; sig2; sig2 = sig2->next)
786                 if (sig2->next == sig)
787                   {
788                     sig2->next = NULL;
789                     break;
790                   }
791             }
792           /* Note that there is no need to release the members of SIG
793              because we won't be here if they have been set. */
794           free (sig);
795           opd->current_sig = NULL;
796         }
797       opd->only_newsig_seen = 0;
798       break;
799
800     case GPGME_STATUS_PLAINTEXT:
801       if (++opd->plaintext_seen > 1)
802         return gpg_error (GPG_ERR_BAD_DATA);
803       err = _gpgme_parse_plaintext (args, &opd->result.file_name);
804       if (err)
805         return err;
806
807     default:
808       break;
809     }
810   return 0;
811 }
812
813
814 static gpgme_error_t
815 verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
816 {
817   gpgme_error_t err;
818
819   err = _gpgme_progress_status_handler (priv, code, args);
820   if (!err)
821     err = _gpgme_verify_status_handler (priv, code, args);
822   return err;
823 }
824
825
826 gpgme_error_t
827 _gpgme_op_verify_init_result (gpgme_ctx_t ctx)
828 {
829   void *hook;
830   op_data_t opd;
831
832   return _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook,
833                                 sizeof (*opd), release_op_data);
834 }
835
836
837 static gpgme_error_t
838 verify_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t sig,
839               gpgme_data_t signed_text, gpgme_data_t plaintext)
840 {
841   gpgme_error_t err;
842
843   err = _gpgme_op_reset (ctx, synchronous);
844   if (err)
845     return err;
846
847   err = _gpgme_op_verify_init_result (ctx);
848   if (err)
849     return err;
850
851   _gpgme_engine_set_status_handler (ctx->engine, verify_status_handler, ctx);
852
853   if (!sig)
854     return gpg_error (GPG_ERR_NO_DATA);
855   if (!signed_text && !plaintext)
856     return gpg_error (GPG_ERR_INV_VALUE);
857
858   return _gpgme_engine_op_verify (ctx->engine, sig, signed_text, plaintext);
859 }
860
861
862 /* Decrypt ciphertext CIPHER and make a signature verification within
863    CTX and store the resulting plaintext in PLAIN.  */
864 gpgme_error_t
865 gpgme_op_verify_start (gpgme_ctx_t ctx, gpgme_data_t sig,
866                        gpgme_data_t signed_text, gpgme_data_t plaintext)
867 {
868   gpg_error_t err;
869   TRACE_BEG3 (DEBUG_CTX, "gpgme_op_verify_start", ctx,
870               "sig=%p, signed_text=%p, plaintext=%p",
871               sig, signed_text, plaintext);
872
873   if (!ctx)
874     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
875
876   err = verify_start (ctx, 0, sig, signed_text, plaintext);
877   return TRACE_ERR (err);
878 }
879
880
881 /* Decrypt ciphertext CIPHER and make a signature verification within
882    CTX and store the resulting plaintext in PLAIN.  */
883 gpgme_error_t
884 gpgme_op_verify (gpgme_ctx_t ctx, gpgme_data_t sig, gpgme_data_t signed_text,
885                  gpgme_data_t plaintext)
886 {
887   gpgme_error_t err;
888
889   TRACE_BEG3 (DEBUG_CTX, "gpgme_op_verify", ctx,
890               "sig=%p, signed_text=%p, plaintext=%p",
891               sig, signed_text, plaintext);
892
893   if (!ctx)
894     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
895
896   err = verify_start (ctx, 1, sig, signed_text, plaintext);
897   if (!err)
898     err = _gpgme_wait_one (ctx);
899   return TRACE_ERR (err);
900 }
901
902 \f
903 /* Compatibility interfaces.  */
904
905 /* Get the key used to create signature IDX in CTX and return it in
906    R_KEY.  */
907 gpgme_error_t
908 gpgme_get_sig_key (gpgme_ctx_t ctx, int idx, gpgme_key_t *r_key)
909 {
910   gpgme_verify_result_t result;
911   gpgme_signature_t sig;
912
913   if (!ctx)
914     return gpg_error (GPG_ERR_INV_VALUE);
915
916   result = gpgme_op_verify_result (ctx);
917   sig = result->signatures;
918
919   while (sig && idx)
920     {
921       sig = sig->next;
922       idx--;
923     }
924   if (!sig || idx)
925     return gpg_error (GPG_ERR_EOF);
926
927   return gpgme_get_key (ctx, sig->fpr, r_key, 0);
928 }
929
930
931 /* Retrieve the signature status of signature IDX in CTX after a
932    successful verify operation in R_STAT (if non-null).  The creation
933    time stamp of the signature is returned in R_CREATED (if non-null).
934    The function returns a string containing the fingerprint.  */
935 const char *
936 gpgme_get_sig_status (gpgme_ctx_t ctx, int idx,
937                       _gpgme_sig_stat_t *r_stat, time_t *r_created)
938 {
939   gpgme_verify_result_t result;
940   gpgme_signature_t sig;
941
942   result = gpgme_op_verify_result (ctx);
943   sig = result->signatures;
944
945   while (sig && idx)
946     {
947       sig = sig->next;
948       idx--;
949     }
950   if (!sig || idx)
951     return NULL;
952
953   if (r_stat)
954     {
955       switch (gpg_err_code (sig->status))
956         {
957         case GPG_ERR_NO_ERROR:
958           *r_stat = GPGME_SIG_STAT_GOOD;
959           break;
960
961         case GPG_ERR_BAD_SIGNATURE:
962           *r_stat = GPGME_SIG_STAT_BAD;
963           break;
964
965         case GPG_ERR_NO_PUBKEY:
966           *r_stat = GPGME_SIG_STAT_NOKEY;
967           break;
968
969         case GPG_ERR_NO_DATA:
970           *r_stat = GPGME_SIG_STAT_NOSIG;
971           break;
972
973         case GPG_ERR_SIG_EXPIRED:
974           *r_stat = GPGME_SIG_STAT_GOOD_EXP;
975           break;
976
977         case GPG_ERR_KEY_EXPIRED:
978           *r_stat = GPGME_SIG_STAT_GOOD_EXPKEY;
979           break;
980
981         default:
982           *r_stat = GPGME_SIG_STAT_ERROR;
983           break;
984         }
985     }
986   if (r_created)
987     *r_created = sig->timestamp;
988   return sig->fpr;
989 }
990
991
992 /* Retrieve certain attributes of a signature.  IDX is the index
993    number of the signature after a successful verify operation.  WHAT
994    is an attribute where GPGME_ATTR_EXPIRE is probably the most useful
995    one.  WHATIDX is to be passed as 0 for most attributes . */
996 unsigned long
997 gpgme_get_sig_ulong_attr (gpgme_ctx_t ctx, int idx,
998                           _gpgme_attr_t what, int whatidx)
999 {
1000   gpgme_verify_result_t result;
1001   gpgme_signature_t sig;
1002
1003   result = gpgme_op_verify_result (ctx);
1004   sig = result->signatures;
1005
1006   while (sig && idx)
1007     {
1008       sig = sig->next;
1009       idx--;
1010     }
1011   if (!sig || idx)
1012     return 0;
1013
1014   switch (what)
1015     {
1016     case GPGME_ATTR_CREATED:
1017       return sig->timestamp;
1018
1019     case GPGME_ATTR_EXPIRE:
1020       return sig->exp_timestamp;
1021
1022     case GPGME_ATTR_VALIDITY:
1023       return (unsigned long) sig->validity;
1024
1025     case GPGME_ATTR_SIG_STATUS:
1026       switch (gpg_err_code (sig->status))
1027         {
1028         case GPG_ERR_NO_ERROR:
1029           return GPGME_SIG_STAT_GOOD;
1030
1031         case GPG_ERR_BAD_SIGNATURE:
1032           return GPGME_SIG_STAT_BAD;
1033
1034         case GPG_ERR_NO_PUBKEY:
1035           return GPGME_SIG_STAT_NOKEY;
1036
1037         case GPG_ERR_NO_DATA:
1038           return GPGME_SIG_STAT_NOSIG;
1039
1040         case GPG_ERR_SIG_EXPIRED:
1041           return GPGME_SIG_STAT_GOOD_EXP;
1042
1043         case GPG_ERR_KEY_EXPIRED:
1044           return GPGME_SIG_STAT_GOOD_EXPKEY;
1045
1046         default:
1047           return GPGME_SIG_STAT_ERROR;
1048         }
1049
1050     case GPGME_ATTR_SIG_SUMMARY:
1051       return sig->summary;
1052
1053     default:
1054       break;
1055     }
1056   return 0;
1057 }
1058
1059
1060 const char *
1061 gpgme_get_sig_string_attr (gpgme_ctx_t ctx, int idx,
1062                            _gpgme_attr_t what, int whatidx)
1063 {
1064   gpgme_verify_result_t result;
1065   gpgme_signature_t sig;
1066
1067   result = gpgme_op_verify_result (ctx);
1068   sig = result->signatures;
1069
1070   while (sig && idx)
1071     {
1072       sig = sig->next;
1073       idx--;
1074     }
1075   if (!sig || idx)
1076     return NULL;
1077
1078   switch (what)
1079     {
1080     case GPGME_ATTR_FPR:
1081       return sig->fpr;
1082
1083     case GPGME_ATTR_ERRTOK:
1084       if (whatidx == 1)
1085         return sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
1086       else
1087         return "";
1088     default:
1089       break;
1090     }
1091
1092   return NULL;
1093 }