* verify.c (strtimestamp_r, gpgsm_verify):
[gnupg.git] / sm / certchain.c
1 /* certchain.c - certificate chain validation
2  *      Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <unistd.h> 
27 #include <time.h>
28 #include <assert.h>
29
30 #include "gpgsm.h"
31 #include <gcrypt.h>
32 #include <ksba.h>
33
34 #include "keydb.h"
35 #include "i18n.h"
36
37 static int
38 unknown_criticals (KsbaCert cert)
39 {
40   static const char *known[] = {
41     "2.5.29.15", /* keyUsage */
42     "2.5.29.19", /* basic Constraints */
43     "2.5.29.32", /* certificatePolicies */
44     NULL
45   };
46   int rc = 0, i, idx, crit;
47   const char *oid;
48   KsbaError err;
49
50   for (idx=0; !(err=ksba_cert_get_extension (cert, idx,
51                                              &oid, &crit, NULL, NULL));idx++)
52     {
53       if (!crit)
54         continue;
55       for (i=0; known[i] && strcmp (known[i],oid); i++)
56         ;
57       if (!known[i])
58         {
59           log_error (_("critical certificate extension %s is not supported\n"),
60                      oid);
61           rc = gpg_error (GPG_ERR_UNSUPPORTED_CERT);
62         }
63     }
64   if (err && err != -1)
65     rc = map_ksba_err (err);
66
67   return rc;
68 }
69
70 static int
71 allowed_ca (KsbaCert cert, int *chainlen)
72 {
73   KsbaError err;
74   int flag;
75
76   err = ksba_cert_is_ca (cert, &flag, chainlen);
77   if (err)
78     return map_ksba_err (err);
79   if (!flag)
80     {
81       log_error (_("issuer certificate is not marked as a CA\n"));
82       return gpg_error (GPG_ERR_BAD_CA_CERT);
83     }
84   return 0;
85 }
86
87
88 static int
89 check_cert_policy (KsbaCert cert)
90 {
91   KsbaError err;
92   char *policies;
93   FILE *fp;
94   int any_critical;
95
96   err = ksba_cert_get_cert_policies (cert, &policies);
97   if (err == KSBA_No_Data)
98     return 0; /* no policy given */
99   if (err)
100     return map_ksba_err (err);
101
102   /* STRING is a line delimited list of certifiate policies as stored
103      in the certificate.  The line itself is colon delimited where the
104      first field is the OID of the policy and the second field either
105      N or C for normal or critical extension */
106
107   if (opt.verbose > 1)
108     log_info ("certificate's policy list: %s\n", policies);
109
110   /* The check is very minimal but won't give false positives */
111   any_critical = !!strstr (policies, ":C");
112
113   if (!opt.policy_file)
114     { 
115       xfree (policies);
116       if (any_critical)
117         {
118           log_error ("critical marked policy without configured policies\n");
119           return gpg_error (GPG_ERR_NO_POLICY_MATCH);
120         }
121       return 0;
122     }
123
124   fp = fopen (opt.policy_file, "r");
125   if (!fp)
126     {
127       log_error ("failed to open `%s': %s\n",
128                  opt.policy_file, strerror (errno));
129       xfree (policies);
130       return gpg_error (GPG_ERR_NO_POLICY_MATCH);
131     }
132
133   for (;;) 
134     {
135       int c;
136       char *p, line[256];
137       char *haystack, *allowed;
138
139       /* read line */
140       do
141         {
142           if (!fgets (line, DIM(line)-1, fp) )
143             {
144               gpg_error_t tmperr;
145
146               xfree (policies);
147               if (feof (fp))
148                 {
149                   fclose (fp);
150                   /* with no critical policies this is only a warning */
151                   if (!any_critical)
152                     {
153                       log_info (_("note: certificate policy not allowed\n"));
154                       return 0;
155                     }
156                   log_error (_("certificate policy not allowed\n"));
157                   return gpg_error (GPG_ERR_NO_POLICY_MATCH);
158                 }
159               tmperr = gpg_error (gpg_err_code_from_errno (errno));
160               fclose (fp);
161               return tmperr;
162             }
163       
164           if (!*line || line[strlen(line)-1] != '\n')
165             {
166               /* eat until end of line */
167               while ( (c=getc (fp)) != EOF && c != '\n')
168                 ;
169               fclose (fp);
170               xfree (policies);
171               return gpg_error (*line? GPG_ERR_LINE_TOO_LONG
172                                      : GPG_ERR_INCOMPLETE_LINE);
173             }
174           
175           /* Allow for empty lines and spaces */
176           for (p=line; spacep (p); p++)
177             ;
178         }
179       while (!*p || *p == '\n' || *p == '#');
180   
181       /* parse line */
182       for (allowed=line; spacep (allowed); allowed++)
183         ;
184       p = strpbrk (allowed, " :\n");
185       if (!*p || p == allowed)
186         {
187           fclose (fp);
188           xfree (policies);
189           return gpg_error (GPG_ERR_CONFIGURATION);
190         }
191       *p = 0; /* strip the rest of the line */
192       /* See whether we find ALLOWED (which is an OID) in POLICIES */
193       for (haystack=policies; (p=strstr (haystack, allowed)); haystack = p+1)
194         {
195           if ( !(p == policies || p[-1] == '\n') )
196             continue; /* does not match the begin of a line */
197           if (p[strlen (allowed)] != ':')
198             continue; /* the length does not match */
199           /* Yep - it does match so return okay */
200           fclose (fp);
201           xfree (policies);
202           return 0;
203         }
204     }
205 }
206
207
208 static void
209 find_up_store_certs_cb (void *cb_value, KsbaCert cert)
210 {
211   if (keydb_store_cert (cert, 1, NULL))
212     log_error ("error storing issuer certificate as ephemeral\n");
213   ++*(int*)cb_value;
214 }
215
216
217 static int
218 find_up (KEYDB_HANDLE kh, KsbaCert cert, const char *issuer)
219 {
220   KsbaName authid;
221   KsbaSexp authidno;
222   int rc = -1;
223
224   if (!ksba_cert_get_auth_key_id (cert, NULL, &authid, &authidno))
225     {
226       const char *s = ksba_name_enum (authid, 0);
227       if (s && *authidno)
228         {
229           rc = keydb_search_issuer_sn (kh, s, authidno);
230           if (rc)
231               keydb_search_reset (kh);
232           if (rc == -1)
233             { /* And try the ephemeral DB. */
234               int old = keydb_set_ephemeral (kh, 1);
235               if (!old)
236                 {
237                   rc = keydb_search_issuer_sn (kh, s, authidno);
238                   if (rc)
239                     keydb_search_reset (kh);
240                 }
241               keydb_set_ephemeral (kh, old);
242             }
243         }
244       /* print a note so that the user does not feel too helpless when
245          an issuer certificate was found and gpgsm prints BAD
246          signature becuase it is not the correct one. */
247       if (rc == -1)
248         {
249           log_info ("issuer certificate (#");
250           gpgsm_dump_serial (authidno);
251           log_printf ("/");
252           gpgsm_dump_string (s);
253           log_printf (") not found\n");
254         }
255       else if (rc)
256         log_error ("failed to find authorityKeyIdentifier: rc=%d\n", rc);
257       ksba_name_release (authid);
258       xfree (authidno);
259       /* Fixme: don't know how to do dirmngr lookup with serial+issuer. */
260     }
261   
262   if (rc) /* not found via authorithyKeyIdentifier, try regular issuer name */
263       rc = keydb_search_subject (kh, issuer);
264   if (rc == -1)
265     {
266       /* Not found, lets see whether we have one in the ephemeral key DB. */
267       int old = keydb_set_ephemeral (kh, 1);
268       if (!old)
269         {
270           keydb_search_reset (kh);
271           rc = keydb_search_subject (kh, issuer);
272         }
273       keydb_set_ephemeral (kh, old);
274     }
275
276   if (rc == -1 && opt.auto_issuer_key_retrieve)
277     {
278       STRLIST names = NULL;
279       int count = 0;
280       char *pattern;
281       const char *s;
282       
283       if (opt.verbose)
284         log_info (_("looking up issuer at external location\n"));
285       /* dirmngr is confused about unknown attributes so has a quick
286          and ugly hack we locate the CN and use this and the
287          following.  Fixme: we should have far better parsing in the
288          dirmngr. */
289       s = strstr (issuer, "CN=");
290       if (!s || s == issuer || s[-1] != ',')
291         s = issuer;
292
293       pattern = xtrymalloc (strlen (s)+2);
294       if (!pattern)
295         return OUT_OF_CORE (errno);
296       strcpy (stpcpy (pattern, "/"), s);
297       add_to_strlist (&names, pattern);
298       xfree (pattern);
299       rc = gpgsm_dirmngr_lookup (NULL, names, find_up_store_certs_cb, &count);
300       free_strlist (names);
301       if (opt.verbose)
302         log_info (_("number of issuers matching: %d\n"), count);
303       if (rc) 
304         {
305           log_error ("external key lookup failed: %s\n", gpg_strerror (rc));
306           rc = -1;
307         }
308       else if (!count)
309         rc = -1;
310       else
311         {
312           int old;
313           /* The issuers are currently stored in the ephemeral key
314              DB, so we temporary switch to ephemeral mode. */
315           old = keydb_set_ephemeral (kh, 1);
316           keydb_search_reset (kh);
317           rc = keydb_search_subject (kh, issuer);
318           keydb_set_ephemeral (kh, old);
319         }
320     }
321   return rc;
322 }
323
324
325 /* Return the next certificate up in the chain starting at START.
326    Returns -1 when there are no more certificates. */
327 int
328 gpgsm_walk_cert_chain (KsbaCert start, KsbaCert *r_next)
329 {
330   int rc = 0; 
331   char *issuer = NULL;
332   char *subject = NULL;
333   KEYDB_HANDLE kh = keydb_new (0);
334
335   *r_next = NULL;
336   if (!kh)
337     {
338       log_error (_("failed to allocated keyDB handle\n"));
339       rc = gpg_error (GPG_ERR_GENERAL);
340       goto leave;
341     }
342
343   issuer = ksba_cert_get_issuer (start, 0);
344   subject = ksba_cert_get_subject (start, 0);
345   if (!issuer)
346     {
347       log_error ("no issuer found in certificate\n");
348       rc = gpg_error (GPG_ERR_BAD_CERT);
349       goto leave;
350     }
351   if (!subject)
352     {
353       log_error ("no subject found in certificate\n");
354       rc = gpg_error (GPG_ERR_BAD_CERT);
355       goto leave;
356     }
357
358   if (!strcmp (issuer, subject))
359     {
360       rc = -1; /* we are at the root */
361       goto leave; 
362     }
363
364   rc = find_up (kh, start, issuer);
365   if (rc)
366     {
367       /* it is quite common not to have a certificate, so better don't
368          print an error here */
369       if (rc != -1 && opt.verbose > 1)
370         log_error ("failed to find issuer's certificate: rc=%d\n", rc);
371       rc = gpg_error (GPG_ERR_MISSING_CERT);
372       goto leave;
373     }
374
375   rc = keydb_get_cert (kh, r_next);
376   if (rc)
377     {
378       log_error ("failed to get cert: rc=%d\n", rc);
379       rc = gpg_error (GPG_ERR_GENERAL);
380     }
381
382  leave:
383   xfree (issuer);
384   xfree (subject);
385   keydb_release (kh); 
386   return rc;
387 }
388
389
390 /* Check whether the CERT is a root certificate.  Returns True if this
391    is the case. */
392 int
393 gpgsm_is_root_cert (KsbaCert cert)
394 {
395   char *issuer;
396   char *subject;
397   int yes;
398
399   issuer = ksba_cert_get_issuer (cert, 0);
400   subject = ksba_cert_get_subject (cert, 0);
401   yes = (issuer && subject && !strcmp (issuer, subject));
402   xfree (issuer);
403   xfree (subject);
404   return yes;
405 }
406
407 \f
408 /* Validate a chain and optionally return the nearest expiration time
409    in R_EXPTIME */
410 int
411 gpgsm_validate_chain (CTRL ctrl, KsbaCert cert, ksba_isotime_t r_exptime)
412 {
413   int rc = 0, depth = 0, maxdepth;
414   char *issuer = NULL;
415   char *subject = NULL;
416   KEYDB_HANDLE kh = keydb_new (0);
417   KsbaCert subject_cert = NULL, issuer_cert = NULL;
418   ksba_isotime_t current_time;
419   ksba_isotime_t exptime;
420   int any_expired = 0;
421   int any_revoked = 0;
422   int any_no_crl = 0;
423   int any_crl_too_old = 0;
424   int any_no_policy_match = 0;
425
426
427   gnupg_get_isotime (current_time);
428   if (r_exptime)
429     *r_exptime = 0;
430   *exptime = 0;
431
432   if (opt.no_chain_validation)
433     {
434       log_info ("WARNING: bypassing certificate chain validation\n");
435       return 0;
436     }
437   
438   if (!kh)
439     {
440       log_error (_("failed to allocated keyDB handle\n"));
441       rc = gpg_error (GPG_ERR_GENERAL);
442       goto leave;
443     }
444
445   if (DBG_X509)
446     gpgsm_dump_cert ("subject", cert);
447
448   subject_cert = cert;
449   maxdepth = 50;
450
451   for (;;)
452     {
453       xfree (issuer);
454       xfree (subject);
455       issuer = ksba_cert_get_issuer (subject_cert, 0);
456       subject = ksba_cert_get_subject (subject_cert, 0);
457
458       if (!issuer)
459         {
460           log_error ("no issuer found in certificate\n");
461           rc = gpg_error (GPG_ERR_BAD_CERT);
462           goto leave;
463         }
464
465       {
466         ksba_isotime_t not_before, not_after;
467
468         rc = ksba_cert_get_validity (subject_cert, 0, not_before);
469         if (!rc)
470           rc = ksba_cert_get_validity (subject_cert, 1, not_after);
471         if (rc)
472           {
473             log_error (_("certificate with invalid validity: %s\n"),
474                        ksba_strerror (rc));
475             rc = gpg_error (GPG_ERR_BAD_CERT);
476             goto leave;
477           }
478
479         if (*not_after)
480           {
481             if (!*exptime)
482               gnupg_copy_time (exptime, not_after);
483             else if (strcmp (not_after, exptime) < 0 )
484               gnupg_copy_time (exptime, not_after);
485           }
486
487         if (*not_before && strcmp (current_time, not_before) < 0 )
488           {
489             log_error ("certificate too young; valid from ");
490             gpgsm_dump_time (not_before);
491             log_printf ("\n");
492             rc = gpg_error (GPG_ERR_CERT_TOO_YOUNG);
493             goto leave;
494           }            
495         if (not_after && strcmp (current_time, not_after) > 0 )
496           {
497             log_error ("certificate has expired at ");
498             gpgsm_dump_time (not_after);
499             log_printf ("\n");
500             any_expired = 1;
501           }            
502       }
503
504       rc = unknown_criticals (subject_cert);
505       if (rc)
506         goto leave;
507
508       if (!opt.no_policy_check)
509         {
510           rc = check_cert_policy (subject_cert);
511           if (gpg_err_code (rc) == GPG_ERR_NO_POLICY_MATCH)
512             {
513               any_no_policy_match = 1;
514               rc = 1;
515             }
516           else if (rc)
517             goto leave;
518         }
519
520       if (!opt.no_crl_check)
521         {
522           rc = gpgsm_dirmngr_isvalid (subject_cert);
523           if (rc)
524             {
525               switch (rc)
526                 {
527                 case GPG_ERR_CERT_REVOKED:
528                   log_error (_("the certificate has been revoked\n"));
529                   any_revoked = 1;
530                   break;
531                 case GPG_ERR_NO_CRL_KNOWN:
532                   log_error (_("no CRL found for certificate\n"));
533                   any_no_crl = 1;
534                   break;
535                 case GPG_ERR_CRL_TOO_OLD:
536                   log_error (_("the available CRL is too old\n"));
537                   log_info (_("please make sure that the "
538                               "\"dirmngr\" is properly installed\n"));
539                   any_crl_too_old = 1;
540                   break;
541                 default:
542                   log_error (_("checking the CRL failed: %s\n"),
543                              gpg_strerror (rc));
544                   goto leave;
545                 }
546               rc = 0;
547             }
548         }
549
550       if (subject && !strcmp (issuer, subject))
551         {
552           if (gpgsm_check_cert_sig (subject_cert, subject_cert) )
553             {
554               log_error ("selfsigned certificate has a BAD signatures\n");
555               rc = gpg_error (depth? GPG_ERR_BAD_CERT_CHAIN
556                                    : GPG_ERR_BAD_CERT);
557               goto leave;
558             }
559           rc = allowed_ca (subject_cert, NULL);
560           if (rc)
561             goto leave;
562
563           rc = gpgsm_agent_istrusted (subject_cert);
564           if (!rc)
565             ;
566           else if (gpg_err_code (rc) == GPG_ERR_NOT_TRUSTED)
567             {
568               int rc2;
569
570               char *fpr = gpgsm_get_fingerprint_string (subject_cert,
571                                                         GCRY_MD_SHA1);
572               log_info (_("root certificate is not marked trusted\n"));
573               log_info (_("fingerprint=%s\n"), fpr? fpr : "?");
574               xfree (fpr);
575               rc2 = gpgsm_agent_marktrusted (subject_cert);
576               if (!rc2)
577                 {
578                   log_info (_("root certificate has now"
579                               " been marked as trusted\n"));
580                   rc = 0;
581                 }
582               else 
583                 {
584                   gpgsm_dump_cert ("issuer", subject_cert);
585                   log_info ("after checking the fingerprint, you may want "
586                             "to enter it manually into "
587                             "\"~/.gnupg-test/trustlist.txt\"\n");
588                 }
589             }
590           else 
591             {
592               log_error (_("checking the trust list failed: %s\n"),
593                          gpg_strerror (rc));
594             }
595           
596           break;  /* okay, a self-signed certicate is an end-point */
597         }
598       
599       depth++;
600       if (depth > maxdepth)
601         {
602           log_error (_("certificate chain too long\n"));
603           rc = gpg_error (GPG_ERR_BAD_CERT_CHAIN);
604           goto leave;
605         }
606
607       /* find the next cert up the tree */
608       keydb_search_reset (kh);
609       rc = find_up (kh, subject_cert, issuer);
610       if (rc)
611         {
612           if (rc == -1)
613             {
614               log_info ("issuer certificate (#/");
615               gpgsm_dump_string (issuer);
616               log_printf (") not found\n");
617             }
618           else
619             log_error ("failed to find issuer's certificate: rc=%d\n", rc);
620           rc = gpg_error (GPG_ERR_MISSING_CERT);
621           goto leave;
622         }
623
624       ksba_cert_release (issuer_cert); issuer_cert = NULL;
625       rc = keydb_get_cert (kh, &issuer_cert);
626       if (rc)
627         {
628           log_error ("failed to get cert: rc=%d\n", rc);
629           rc = gpg_error (GPG_ERR_GENERAL);
630           goto leave;
631         }
632
633       if (DBG_X509)
634         {
635           log_debug ("got issuer's certificate:\n");
636           gpgsm_dump_cert ("issuer", issuer_cert);
637         }
638
639       if (gpgsm_check_cert_sig (issuer_cert, subject_cert) )
640         {
641           log_error ("certificate has a BAD signatures\n");
642           rc = gpg_error (GPG_ERR_BAD_CERT_CHAIN);
643           goto leave;
644         }
645
646       {
647         int chainlen;
648         rc = allowed_ca (issuer_cert, &chainlen);
649         if (rc)
650           goto leave;
651         if (chainlen >= 0 && (depth - 1) > chainlen)
652           {
653             log_error (_("certificate chain longer than allowed by CA (%d)\n"),
654                        chainlen);
655             rc = gpg_error (GPG_ERR_BAD_CERT_CHAIN);
656             goto leave;
657           }
658       }
659
660       rc = gpgsm_cert_use_cert_p (issuer_cert);
661       if (rc)
662         {
663           char numbuf[50];
664           sprintf (numbuf, "%d", rc);
665           gpgsm_status2 (ctrl, STATUS_ERROR, "certcert.issuer.keyusage",
666                          numbuf, NULL);
667           rc = 0;
668         }
669
670       if (opt.verbose)
671         log_info ("certificate is good\n");
672       
673       keydb_search_reset (kh);
674       subject_cert = issuer_cert;
675       issuer_cert = NULL;
676     }
677
678   if (opt.no_policy_check)
679     log_info ("policies not checked due to --disable-policy-checks option\n");
680   if (opt.no_crl_check)
681     log_info ("CRLs not checked due to --disable-crl-checks option\n");
682
683   if (!rc)
684     { /* If we encountered an error somewhere during the checks, set
685          the error code to the most critical one */
686       if (any_revoked)
687         rc = gpg_error (GPG_ERR_CERT_REVOKED);
688       else if (any_no_crl)
689         rc = gpg_error (GPG_ERR_NO_CRL_KNOWN);
690       else if (any_crl_too_old)
691         rc = gpg_error (GPG_ERR_CRL_TOO_OLD);
692       else if (any_no_policy_match)
693         rc = gpg_error (GPG_ERR_NO_POLICY_MATCH);
694       else if (any_expired)
695         rc = gpg_error (GPG_ERR_CERT_EXPIRED);
696     }
697   
698  leave:
699   if (r_exptime)
700     gnupg_copy_time (r_exptime, exptime);
701   xfree (issuer);
702   keydb_release (kh); 
703   ksba_cert_release (issuer_cert);
704   if (subject_cert != cert)
705     ksba_cert_release (subject_cert);
706   return rc;
707 }
708
709
710 /* Check that the given certificate is valid but DO NOT check any
711    constraints.  We assume that the issuers certificate is already in
712    the DB and that this one is valid; which it should be because it
713    has been checked using this function. */
714 int
715 gpgsm_basic_cert_check (KsbaCert cert)
716 {
717   int rc = 0;
718   char *issuer = NULL;
719   char *subject = NULL;
720   KEYDB_HANDLE kh = keydb_new (0);
721   KsbaCert issuer_cert = NULL;
722
723   if (opt.no_chain_validation)
724     {
725       log_info ("WARNING: bypassing basic certificate checks\n");
726       return 0;
727     }
728
729   if (!kh)
730     {
731       log_error (_("failed to allocated keyDB handle\n"));
732       rc = gpg_error (GPG_ERR_GENERAL);
733       goto leave;
734     }
735
736   issuer = ksba_cert_get_issuer (cert, 0);
737   subject = ksba_cert_get_subject (cert, 0);
738   if (!issuer)
739     {
740       log_error ("no issuer found in certificate\n");
741       rc = gpg_error (GPG_ERR_BAD_CERT);
742       goto leave;
743     }
744
745   if (subject && !strcmp (issuer, subject))
746     {
747       if (gpgsm_check_cert_sig (cert, cert) )
748         {
749           log_error ("selfsigned certificate has a BAD signatures\n");
750           rc = gpg_error (GPG_ERR_BAD_CERT);
751           goto leave;
752         }
753     }
754   else
755     {
756       /* find the next cert up the tree */
757       keydb_search_reset (kh);
758       rc = find_up (kh, cert, issuer);
759       if (rc)
760         {
761           if (rc == -1)
762             {
763               log_info ("issuer certificate (#/");
764               gpgsm_dump_string (issuer);
765               log_printf (") not found\n");
766             }
767           else
768             log_error ("failed to find issuer's certificate: rc=%d\n", rc);
769           rc = gpg_error (GPG_ERR_MISSING_CERT);
770           goto leave;
771         }
772       
773       ksba_cert_release (issuer_cert); issuer_cert = NULL;
774       rc = keydb_get_cert (kh, &issuer_cert);
775       if (rc)
776         {
777           log_error ("failed to get cert: rc=%d\n", rc);
778           rc = gpg_error (GPG_ERR_GENERAL);
779           goto leave;
780         }
781
782       if (gpgsm_check_cert_sig (issuer_cert, cert) )
783         {
784           log_error ("certificate has a BAD signatures\n");
785           rc = gpg_error (GPG_ERR_BAD_CERT);
786           goto leave;
787         }
788       if (opt.verbose)
789         log_info ("certificate is good\n");
790     }
791
792  leave:
793   xfree (issuer);
794   keydb_release (kh); 
795   ksba_cert_release (issuer_cert);
796   return rc;
797 }
798