2003-05-27 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / gpgme / verify.c
1 /* verify.c - Signature verification.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003 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 General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (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    General Public License for more details.
16  
17    You should have received a copy of the GNU General Public License
18    along with GPGME; if not, write to the Free Software Foundation,
19    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27
28 #include "gpgme.h"
29 #include "util.h"
30 #include "context.h"
31 #include "ops.h"
32
33 \f
34 typedef struct
35 {
36   struct _gpgme_op_verify_result result;
37
38   gpgme_signature_t current_sig;
39 } *op_data_t;
40
41
42 static void
43 release_op_data (void *hook)
44 {
45   op_data_t opd = (op_data_t) hook;
46   gpgme_signature_t sig = opd->result.signatures;
47
48   while (sig)
49     {
50       gpgme_signature_t next = sig->next;
51       gpgme_sig_notation_t notation = sig->notations;
52
53       while (notation)
54         {
55           gpgme_sig_notation_t next_nota = notation->next;
56
57           if (notation->name)
58             free (notation->name);
59           if (notation->value)
60             free (notation->value);
61           notation = next_nota;
62         }
63
64       if (sig->fpr)
65         free (sig->fpr);
66       free (sig);
67       sig = next;
68     }
69 }
70
71
72 gpgme_verify_result_t
73 gpgme_op_verify_result (gpgme_ctx_t ctx)
74 {
75   void *hook;
76   op_data_t opd;
77   gpgme_error_t err;
78
79   err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook, -1, NULL);
80   opd = hook;
81   if (err || !opd)
82     return NULL;
83
84   return &opd->result;
85 }
86
87 \f
88 /* Build a summary vector from RESULT. */
89 static void
90 calc_sig_summary (gpgme_signature_t sig)
91 {
92   unsigned long sum = 0;
93
94   if (sig->validity == GPGME_VALIDITY_FULL
95       || sig->validity == GPGME_VALIDITY_ULTIMATE)
96     {
97       if (sig->status == GPGME_No_Error
98           || sig->status == GPGME_Sig_Expired
99           || sig->status == GPGME_Key_Expired)
100         sum |= GPGME_SIGSUM_GREEN;
101     }
102   else if (sig->validity == GPGME_VALIDITY_NEVER)
103     {
104       if (sig->status == GPGME_No_Error
105           || sig->status == GPGME_Sig_Expired
106           || sig->status == GPGME_Key_Expired)
107         sum |= GPGME_SIGSUM_RED;
108     }
109   else if (sig->status == GPGME_Bad_Signature)
110     sum |= GPGME_SIGSUM_RED;
111   
112   /* FIXME: handle the case when key and message are expired. */
113   switch (sig->status)
114     {
115     case GPGME_Sig_Expired:
116       sum |= GPGME_SIGSUM_SIG_EXPIRED;
117       break;
118
119     case GPGME_Key_Expired:
120       sum |= GPGME_SIGSUM_KEY_EXPIRED;
121       break;
122
123     case GPGME_No_Public_Key:
124       sum |= GPGME_SIGSUM_KEY_MISSING;
125       break;
126
127     case GPGME_Bad_Signature:
128     case GPGME_No_Error:
129       break;
130
131     default:
132       sum |= GPGME_SIGSUM_SYS_ERROR;
133       break;
134     }
135   
136   if (sig->wrong_key_usage)
137     sum |= GPGME_SIGSUM_BAD_POLICY;
138   
139   /* Set the valid flag when the signature is unquestionable
140      valid. */
141   if ((sum & GPGME_SIGSUM_GREEN) && !(sum & ~GPGME_SIGSUM_GREEN))
142     sum |= GPGME_SIGSUM_VALID;
143   
144   sig->summary = sum;
145 }
146   
147
148 static gpgme_error_t
149 parse_new_sig (op_data_t opd, gpgme_status_code_t code, char *args)
150 {
151   gpgme_signature_t sig;
152   char *end = strchr (args, ' ');
153
154   if (end)
155     {
156       *end = '\0';
157       end++;
158     }
159
160   sig = calloc (1, sizeof (*sig));
161   if (!sig)
162     return GPGME_Out_Of_Core;
163   if (!opd->result.signatures)
164     opd->result.signatures = sig;
165   if (opd->current_sig)
166     opd->current_sig->next = sig;
167   opd->current_sig = sig;
168
169   switch (code)
170     {
171     case GPGME_STATUS_GOODSIG:
172       sig->status = GPGME_No_Error;
173       break;
174
175     case GPGME_STATUS_EXPSIG:
176       sig->status = GPGME_Sig_Expired;
177       break;
178
179     case GPGME_STATUS_EXPKEYSIG:
180       sig->status = GPGME_Key_Expired;
181       break;
182
183     case GPGME_STATUS_BADSIG:
184       sig->status = GPGME_Bad_Signature;
185       break;
186
187     case GPGME_STATUS_ERRSIG:
188       if (end)
189         {
190           int i = 0;
191           /* The return code is the 6th argument, if it is 9, the
192              problem is a missing key.  */
193           while (end && i < 4)
194             {
195               end = strchr (end, ' ');
196               if (end)
197                 end++;
198               i++;
199             }
200           if (end && end[0] && (!end[1] || !end[1] == ' '))
201             {
202               switch (end[0])
203                 {
204                 case '4':
205                   sig->status = GPGME_Unsupported_Algorithm;
206                   break;
207
208                 case 9:
209                   sig->status = GPGME_No_Public_Key;
210                   break;
211
212                 default:
213                   sig->status = GPGME_General_Error;
214                 }
215             }
216         }
217       else
218         sig->status = GPGME_General_Error;
219       break;
220
221     default:
222       return GPGME_General_Error;
223     }
224
225   if (*args)
226     {
227       sig->fpr = strdup (args);
228       if (!sig->fpr)
229         return GPGME_Out_Of_Core;
230     }
231   return 0;
232 }
233
234
235 static gpgme_error_t
236 parse_valid_sig (gpgme_signature_t sig, char *args)
237 {
238   char *end = strchr (args, ' ');
239
240   if (end)
241     {
242       *end = '\0';
243       end++;
244     }
245
246   if (!*args)
247     /* We require at least the fingerprint.  */
248     return GPGME_General_Error;
249
250   if (sig->fpr)
251     free (sig->fpr);
252   sig->fpr = strdup (args);
253   if (!sig->fpr)
254     return GPGME_Out_Of_Core;
255
256   end = strchr (end, ' ');
257   if (end)
258     {
259       char *tail;
260       errno = 0;
261       sig->timestamp = strtol (end, &tail, 0);
262       if (errno || end == tail || (*tail && *tail != ' '))
263         return GPGME_General_Error;
264       end = tail;
265      
266       sig->exp_timestamp = strtol (end, &tail, 0);
267       if (errno || end == tail || (*tail && *tail != ' '))
268         return GPGME_General_Error;
269     }
270   return 0;
271 }
272
273
274 static gpgme_error_t
275 parse_notation (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
276 {
277   gpgme_error_t err;
278   gpgme_sig_notation_t *lastp = &sig->notations;
279   gpgme_sig_notation_t notation = sig->notations;
280   char *end = strchr (args, ' ');
281
282   if (end)
283     *end = '\0';
284
285   if (code == GPGME_STATUS_NOTATION_NAME || code == GPGME_STATUS_POLICY_URL)
286     {
287       /* FIXME: We could keep a pointer to the last notation in the list.  */
288       while (notation && notation->value)
289         {
290           lastp = &notation->next;
291           notation = notation->next;
292         }
293
294       if (notation)
295         /* There is another notation name without data for the
296            previous one.  The crypto backend misbehaves.  */
297         return GPGME_General_Error;
298
299       notation = malloc (sizeof (*sig));
300       if (!notation)
301         return GPGME_Out_Of_Core;
302       notation->next = NULL;
303
304       if (code == GPGME_STATUS_NOTATION_NAME)
305         {
306           int len = strlen (args) + 1;
307
308           notation->name = malloc (len);
309           if (!notation->name)
310             {
311               free (notation);
312               return GPGME_Out_Of_Core;
313             }
314           err = _gpgme_decode_percent_string (args, &notation->name, len);
315           if (err)
316             return err;
317
318           notation->value = NULL;
319         }
320       else
321         {
322           int len = strlen (args) + 1;
323
324           notation->name = NULL;
325           notation->value = malloc (len);
326           if (!notation->value)
327             {
328               free (notation);
329               return GPGME_Out_Of_Core;
330             }
331           err = _gpgme_decode_percent_string (args, &notation->value, len);
332           if (err)
333             return err;
334         }
335       *lastp = notation;
336     }
337   else if (code == GPGME_STATUS_NOTATION_DATA)
338     {
339       int len = strlen (args) + 1;
340       char *dest;
341
342       /* FIXME: We could keep a pointer to the last notation in the list.  */
343       while (notation && notation->next)
344         {
345           lastp = &notation->next;
346           notation = notation->next;
347         }
348
349       if (!notation || !notation->name)
350         /* There is notation data without a previous notation
351            name.  The crypto backend misbehaves.  */
352         return GPGME_General_Error;
353       
354       if (!notation->value)
355         {
356           dest = notation->value = malloc (len);
357           if (!dest)
358             return GPGME_Out_Of_Core;
359         }
360       else
361         {
362           int cur_len = strlen (notation->value);
363           dest = realloc (notation->value, len + strlen (notation->value));
364           if (!dest)
365             return GPGME_Out_Of_Core;
366           notation->value = dest;
367           dest += cur_len;
368         }
369       
370       err = _gpgme_decode_percent_string (args, &dest, len);
371       if (err)
372         return err;
373     }
374   else
375     return GPGME_General_Error;
376   return 0;
377 }
378
379
380 static gpgme_error_t
381 parse_trust (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
382 {
383   char *end = strchr (args, ' ');
384
385   if (end)
386     *end = '\0';
387
388   switch (code)
389     {
390     case GPGME_STATUS_TRUST_UNDEFINED:
391     default:
392       sig->validity = GPGME_VALIDITY_UNKNOWN;
393       break;
394
395     case GPGME_STATUS_TRUST_NEVER:
396       sig->validity = GPGME_VALIDITY_NEVER;
397       break;
398
399     case GPGME_STATUS_TRUST_MARGINAL:
400       sig->validity = GPGME_VALIDITY_MARGINAL;
401       break;
402
403     case GPGME_STATUS_TRUST_FULLY:
404     case GPGME_STATUS_TRUST_ULTIMATE:
405       sig->validity = GPGME_VALIDITY_FULL;
406       break;
407     }
408
409   if (*args)
410     sig->validity_reason = _gpgme_map_gnupg_error (args);
411
412   return 0;
413 }
414
415
416 static gpgme_error_t
417 parse_error (gpgme_signature_t sig, char *args)
418 {
419   gpgme_error_t err;
420   char *where = strchr (args, ' ');
421   char *which;
422
423   if (where)
424     {
425       *where = '\0';
426       which = where + 1;
427
428       where = strchr (which, ' ');
429       if (where)
430         *where = '\0';
431
432       where = args;      
433     }
434   else
435     return GPGME_General_Error;
436
437   err = _gpgme_map_gnupg_error (which);
438
439   if (!strcmp (where, "verify.findkey"))
440     sig->status = err;
441   else if (!strcmp (where, "verify.keyusage") && err == GPGME_Wrong_Key_Usage)
442     sig->wrong_key_usage = 1;
443
444   return 0;
445 }
446
447
448 gpgme_error_t
449 _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
450 {
451   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
452   gpgme_error_t err;
453   void *hook;
454   op_data_t opd;
455   gpgme_signature_t sig;
456
457   err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook, -1, NULL);
458   opd = hook;
459   if (err)
460     return err;
461
462   sig = opd->current_sig;
463
464   switch (code)
465     {
466     case GPGME_STATUS_GOODSIG:
467     case GPGME_STATUS_EXPSIG:
468     case GPGME_STATUS_EXPKEYSIG:
469     case GPGME_STATUS_BADSIG:
470     case GPGME_STATUS_ERRSIG:
471       if (sig)
472         calc_sig_summary (sig);
473       return parse_new_sig (opd, code, args);
474
475     case GPGME_STATUS_VALIDSIG:
476       return sig ? parse_valid_sig (sig, args) : GPGME_General_Error;
477
478     case GPGME_STATUS_NODATA:
479       if (!sig)
480         return GPGME_No_Data;
481       sig->status = GPGME_No_Data;
482       break;
483
484     case GPGME_STATUS_UNEXPECTED:
485       if (!sig)
486         return GPGME_General_Error;
487       sig->status = GPGME_No_Data;
488       break;
489
490     case GPGME_STATUS_NOTATION_NAME:
491     case GPGME_STATUS_NOTATION_DATA:
492     case GPGME_STATUS_POLICY_URL:
493       return sig ? parse_notation (sig, code, args) : GPGME_General_Error;
494
495     case GPGME_STATUS_TRUST_UNDEFINED:
496     case GPGME_STATUS_TRUST_NEVER:
497     case GPGME_STATUS_TRUST_MARGINAL:
498     case GPGME_STATUS_TRUST_FULLY:
499     case GPGME_STATUS_TRUST_ULTIMATE:
500       return sig ? parse_trust (sig, code, args) : GPGME_General_Error;
501
502     case GPGME_STATUS_ERROR:
503       return sig ? parse_error (sig, args) : GPGME_General_Error;
504
505     case GPGME_STATUS_EOF:
506       if (sig)
507         calc_sig_summary (sig);
508       break;
509
510     default:
511       break;
512     }
513   return 0;
514 }
515
516
517 static gpgme_error_t
518 verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
519 {
520   return _gpgme_progress_status_handler (priv, code, args)
521     || _gpgme_verify_status_handler (priv, code, args);
522 }
523
524
525 gpgme_error_t
526 _gpgme_op_verify_init_result (gpgme_ctx_t ctx)
527 {  
528   void *hook;
529   op_data_t opd;
530
531   return _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook,
532                                 sizeof (*opd), release_op_data);
533 }
534
535
536 static gpgme_error_t
537 verify_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t sig,
538               gpgme_data_t signed_text, gpgme_data_t plaintext)
539 {
540   gpgme_error_t err;
541
542   err = _gpgme_op_reset (ctx, synchronous);
543   if (err)
544     return err;
545
546   err = _gpgme_op_verify_init_result (ctx);
547   if (err)
548     return err;
549
550   _gpgme_engine_set_status_handler (ctx->engine, verify_status_handler, ctx);
551
552   if (!sig)
553     return GPGME_No_Data;
554   if (!signed_text && !plaintext)
555     return GPGME_Invalid_Value;
556
557   return _gpgme_engine_op_verify (ctx->engine, sig, signed_text, plaintext);
558 }
559
560
561 /* Decrypt ciphertext CIPHER and make a signature verification within
562    CTX and store the resulting plaintext in PLAIN.  */
563 gpgme_error_t
564 gpgme_op_verify_start (gpgme_ctx_t ctx, gpgme_data_t sig,
565                        gpgme_data_t signed_text, gpgme_data_t plaintext)
566 {
567   return verify_start (ctx, 0, sig, signed_text, plaintext);
568 }
569
570
571 /* Decrypt ciphertext CIPHER and make a signature verification within
572    CTX and store the resulting plaintext in PLAIN.  */
573 gpgme_error_t
574 gpgme_op_verify (gpgme_ctx_t ctx, gpgme_data_t sig, gpgme_data_t signed_text,
575                  gpgme_data_t plaintext)
576 {
577   gpgme_error_t err;
578
579   err = verify_start (ctx, 1, sig, signed_text, plaintext);
580   if (!err)
581     err = _gpgme_wait_one (ctx);
582   return err;
583 }
584
585 \f
586 /* Compatibility interfaces.  */
587
588 /* Get the key used to create signature IDX in CTX and return it in
589    R_KEY.  */
590 gpgme_error_t
591 gpgme_get_sig_key (gpgme_ctx_t ctx, int idx, gpgme_key_t *r_key)
592 {
593   gpgme_verify_result_t result;
594   gpgme_signature_t sig;
595
596   result = gpgme_op_verify_result (ctx);
597   sig = result->signatures;
598
599   while (sig && idx)
600     {
601       sig = sig->next;
602       idx--;
603     }
604   if (!sig || idx)
605     return GPGME_EOF;
606
607   return gpgme_get_key (ctx, sig->fpr, r_key, 0);
608 }
609
610
611 /* Retrieve the signature status of signature IDX in CTX after a
612    successful verify operation in R_STAT (if non-null).  The creation
613    time stamp of the signature is returned in R_CREATED (if non-null).
614    The function returns a string containing the fingerprint.  */
615 const char *gpgme_get_sig_status (gpgme_ctx_t ctx, int idx,
616                                   _gpgme_sig_stat_t *r_stat, time_t *r_created)
617 {
618   gpgme_verify_result_t result;
619   gpgme_signature_t sig;
620
621   result = gpgme_op_verify_result (ctx);
622   sig = result->signatures;
623
624   while (sig && idx)
625     {
626       sig = sig->next;
627       idx--;
628     }
629   if (!sig || idx)
630     return NULL;
631
632   if (r_stat)
633     {
634       switch (sig->status)
635         {
636         case GPGME_No_Error:
637           *r_stat = GPGME_SIG_STAT_GOOD;
638           break;
639           
640         case GPGME_Bad_Signature:
641           *r_stat = GPGME_SIG_STAT_BAD;
642           break;
643           
644         case GPGME_No_Public_Key:
645           *r_stat = GPGME_SIG_STAT_NOKEY;
646           break;
647           
648         case GPGME_No_Data:
649           *r_stat = GPGME_SIG_STAT_NOSIG;
650           break;
651           
652         case GPGME_Sig_Expired:
653           *r_stat = GPGME_SIG_STAT_GOOD_EXP;
654           break;
655           
656         case GPGME_Key_Expired:
657           *r_stat = GPGME_SIG_STAT_GOOD_EXPKEY;
658           break;
659           
660         default:
661           *r_stat = GPGME_SIG_STAT_ERROR;
662           break;
663         }
664     }
665   if (r_created)
666     *r_created = sig->timestamp;
667   return sig->fpr;
668 }
669
670
671 /* Retrieve certain attributes of a signature.  IDX is the index
672    number of the signature after a successful verify operation.  WHAT
673    is an attribute where GPGME_ATTR_EXPIRE is probably the most useful
674    one.  WHATIDX is to be passed as 0 for most attributes . */
675 unsigned long gpgme_get_sig_ulong_attr (gpgme_ctx_t ctx, int idx,
676                                         _gpgme_attr_t what, int whatidx)
677 {
678   gpgme_verify_result_t result;
679   gpgme_signature_t sig;
680
681   result = gpgme_op_verify_result (ctx);
682   sig = result->signatures;
683
684   while (sig && idx)
685     {
686       sig = sig->next;
687       idx--;
688     }
689   if (!sig || idx)
690     return 0;
691
692   switch (what)
693     {
694     case GPGME_ATTR_CREATED:
695       return sig->timestamp;
696
697     case GPGME_ATTR_EXPIRE:
698       return sig->exp_timestamp;
699
700     case GPGME_ATTR_VALIDITY:
701       return (unsigned long) sig->validity;
702
703     case GPGME_ATTR_SIG_STATUS:
704       switch (sig->status)
705         {
706         case GPGME_No_Error:
707           return GPGME_SIG_STAT_GOOD;
708           
709         case GPGME_Bad_Signature:
710           return GPGME_SIG_STAT_BAD;
711           
712         case GPGME_No_Public_Key:
713           return GPGME_SIG_STAT_NOKEY;
714           
715         case GPGME_No_Data:
716           return GPGME_SIG_STAT_NOSIG;
717           
718         case GPGME_Sig_Expired:
719           return GPGME_SIG_STAT_GOOD_EXP;
720           
721         case GPGME_Key_Expired:
722           return GPGME_SIG_STAT_GOOD_EXPKEY;
723           
724         default:
725           return GPGME_SIG_STAT_ERROR;
726         }
727
728     case GPGME_ATTR_SIG_SUMMARY:
729       return sig->summary;
730
731     default:
732       break;
733     }
734   return 0;
735 }
736
737
738 const char *gpgme_get_sig_string_attr (gpgme_ctx_t ctx, int idx,
739                                       _gpgme_attr_t what, int whatidx)
740 {
741   gpgme_verify_result_t result;
742   gpgme_signature_t sig;
743
744   result = gpgme_op_verify_result (ctx);
745   sig = result->signatures;
746
747   while (sig && idx)
748     {
749       sig = sig->next;
750       idx--;
751     }
752   if (!sig || idx)
753     return NULL;
754
755   switch (what)
756     {
757     case GPGME_ATTR_FPR:
758       return sig->fpr;
759
760     case GPGME_ATTR_ERRTOK:
761       if (whatidx == 1)
762         return sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
763       else
764         return "";
765     default:
766       break;
767     }
768
769   return NULL;
770 }