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