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