api: Remove arbitrary restriction from gpgme_op_verify.
[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
865   return _gpgme_engine_op_verify (ctx->engine, sig, signed_text, plaintext);
866 }
867
868
869 /* Decrypt ciphertext CIPHER and make a signature verification within
870    CTX and store the resulting plaintext in PLAIN.  */
871 gpgme_error_t
872 gpgme_op_verify_start (gpgme_ctx_t ctx, gpgme_data_t sig,
873                        gpgme_data_t signed_text, gpgme_data_t plaintext)
874 {
875   gpg_error_t err;
876   TRACE_BEG3 (DEBUG_CTX, "gpgme_op_verify_start", ctx,
877               "sig=%p, signed_text=%p, plaintext=%p",
878               sig, signed_text, plaintext);
879
880   if (!ctx)
881     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
882
883   err = verify_start (ctx, 0, sig, signed_text, plaintext);
884   return TRACE_ERR (err);
885 }
886
887
888 /* Decrypt ciphertext CIPHER and make a signature verification within
889    CTX and store the resulting plaintext in PLAIN.  */
890 gpgme_error_t
891 gpgme_op_verify (gpgme_ctx_t ctx, gpgme_data_t sig, gpgme_data_t signed_text,
892                  gpgme_data_t plaintext)
893 {
894   gpgme_error_t err;
895
896   TRACE_BEG3 (DEBUG_CTX, "gpgme_op_verify", ctx,
897               "sig=%p, signed_text=%p, plaintext=%p",
898               sig, signed_text, plaintext);
899
900   if (!ctx)
901     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
902
903   err = verify_start (ctx, 1, sig, signed_text, plaintext);
904   if (!err)
905     err = _gpgme_wait_one (ctx);
906   return TRACE_ERR (err);
907 }
908
909 \f
910 /* Compatibility interfaces.  */
911
912 /* Get the key used to create signature IDX in CTX and return it in
913    R_KEY.  */
914 gpgme_error_t
915 gpgme_get_sig_key (gpgme_ctx_t ctx, int idx, gpgme_key_t *r_key)
916 {
917   gpgme_verify_result_t result;
918   gpgme_signature_t sig;
919
920   if (!ctx)
921     return gpg_error (GPG_ERR_INV_VALUE);
922
923   result = gpgme_op_verify_result (ctx);
924   sig = result->signatures;
925
926   while (sig && idx)
927     {
928       sig = sig->next;
929       idx--;
930     }
931   if (!sig || idx)
932     return gpg_error (GPG_ERR_EOF);
933
934   return gpgme_get_key (ctx, sig->fpr, r_key, 0);
935 }
936
937
938 /* Retrieve the signature status of signature IDX in CTX after a
939    successful verify operation in R_STAT (if non-null).  The creation
940    time stamp of the signature is returned in R_CREATED (if non-null).
941    The function returns a string containing the fingerprint.  */
942 const char *
943 gpgme_get_sig_status (gpgme_ctx_t ctx, int idx,
944                       _gpgme_sig_stat_t *r_stat, time_t *r_created)
945 {
946   gpgme_verify_result_t result;
947   gpgme_signature_t sig;
948
949   result = gpgme_op_verify_result (ctx);
950   sig = result->signatures;
951
952   while (sig && idx)
953     {
954       sig = sig->next;
955       idx--;
956     }
957   if (!sig || idx)
958     return NULL;
959
960   if (r_stat)
961     {
962       switch (gpg_err_code (sig->status))
963         {
964         case GPG_ERR_NO_ERROR:
965           *r_stat = GPGME_SIG_STAT_GOOD;
966           break;
967
968         case GPG_ERR_BAD_SIGNATURE:
969           *r_stat = GPGME_SIG_STAT_BAD;
970           break;
971
972         case GPG_ERR_NO_PUBKEY:
973           *r_stat = GPGME_SIG_STAT_NOKEY;
974           break;
975
976         case GPG_ERR_NO_DATA:
977           *r_stat = GPGME_SIG_STAT_NOSIG;
978           break;
979
980         case GPG_ERR_SIG_EXPIRED:
981           *r_stat = GPGME_SIG_STAT_GOOD_EXP;
982           break;
983
984         case GPG_ERR_KEY_EXPIRED:
985           *r_stat = GPGME_SIG_STAT_GOOD_EXPKEY;
986           break;
987
988         default:
989           *r_stat = GPGME_SIG_STAT_ERROR;
990           break;
991         }
992     }
993   if (r_created)
994     *r_created = sig->timestamp;
995   return sig->fpr;
996 }
997
998
999 /* Retrieve certain attributes of a signature.  IDX is the index
1000    number of the signature after a successful verify operation.  WHAT
1001    is an attribute where GPGME_ATTR_EXPIRE is probably the most useful
1002    one.  WHATIDX is to be passed as 0 for most attributes . */
1003 unsigned long
1004 gpgme_get_sig_ulong_attr (gpgme_ctx_t ctx, int idx,
1005                           _gpgme_attr_t what, int whatidx)
1006 {
1007   gpgme_verify_result_t result;
1008   gpgme_signature_t sig;
1009
1010   result = gpgme_op_verify_result (ctx);
1011   sig = result->signatures;
1012
1013   while (sig && idx)
1014     {
1015       sig = sig->next;
1016       idx--;
1017     }
1018   if (!sig || idx)
1019     return 0;
1020
1021   switch (what)
1022     {
1023     case GPGME_ATTR_CREATED:
1024       return sig->timestamp;
1025
1026     case GPGME_ATTR_EXPIRE:
1027       return sig->exp_timestamp;
1028
1029     case GPGME_ATTR_VALIDITY:
1030       return (unsigned long) sig->validity;
1031
1032     case GPGME_ATTR_SIG_STATUS:
1033       switch (gpg_err_code (sig->status))
1034         {
1035         case GPG_ERR_NO_ERROR:
1036           return GPGME_SIG_STAT_GOOD;
1037
1038         case GPG_ERR_BAD_SIGNATURE:
1039           return GPGME_SIG_STAT_BAD;
1040
1041         case GPG_ERR_NO_PUBKEY:
1042           return GPGME_SIG_STAT_NOKEY;
1043
1044         case GPG_ERR_NO_DATA:
1045           return GPGME_SIG_STAT_NOSIG;
1046
1047         case GPG_ERR_SIG_EXPIRED:
1048           return GPGME_SIG_STAT_GOOD_EXP;
1049
1050         case GPG_ERR_KEY_EXPIRED:
1051           return GPGME_SIG_STAT_GOOD_EXPKEY;
1052
1053         default:
1054           return GPGME_SIG_STAT_ERROR;
1055         }
1056
1057     case GPGME_ATTR_SIG_SUMMARY:
1058       return sig->summary;
1059
1060     default:
1061       break;
1062     }
1063   return 0;
1064 }
1065
1066
1067 const char *
1068 gpgme_get_sig_string_attr (gpgme_ctx_t ctx, int idx,
1069                            _gpgme_attr_t what, int whatidx)
1070 {
1071   gpgme_verify_result_t result;
1072   gpgme_signature_t sig;
1073
1074   result = gpgme_op_verify_result (ctx);
1075   sig = result->signatures;
1076
1077   while (sig && idx)
1078     {
1079       sig = sig->next;
1080       idx--;
1081     }
1082   if (!sig || idx)
1083     return NULL;
1084
1085   switch (what)
1086     {
1087     case GPGME_ATTR_FPR:
1088       return sig->fpr;
1089
1090     case GPGME_ATTR_ERRTOK:
1091       if (whatidx == 1)
1092         return sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
1093       else
1094         return "";
1095     default:
1096       break;
1097     }
1098
1099   return NULL;
1100 }