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