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