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