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