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