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