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