* gpgsm.c (main): Set the prefixes for assuan logging.
[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 && gpg_err_code (err) != GPG_ERR_EOF)
65     rc = 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 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 (gpg_err_code (err) == GPG_ERR_NO_DATA)
98     return 0; /* no policy given */
99   if (err)
100     return 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                        gpg_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 || ctrl->use_ocsp)
521         {
522           rc = gpgsm_dirmngr_isvalid (subject_cert, ctrl->use_ocsp);
523           if (rc)
524             {
525               /* Fixme: We should change the wording because we may
526                  have used OCSP. */
527               switch (gpg_err_code (rc))
528                 {
529                 case GPG_ERR_CERT_REVOKED:
530                   log_error (_("the certificate has been revoked\n"));
531                   any_revoked = 1;
532                   break;
533                 case GPG_ERR_NO_CRL_KNOWN:
534                   log_error (_("no CRL found for certificate\n"));
535                   any_no_crl = 1;
536                   break;
537                 case GPG_ERR_CRL_TOO_OLD:
538                   log_error (_("the available CRL is too old\n"));
539                   log_info (_("please make sure that the "
540                               "\"dirmngr\" is properly installed\n"));
541                   any_crl_too_old = 1;
542                   break;
543                 default:
544                   log_error (_("checking the CRL failed: %s\n"),
545                              gpg_strerror (rc));
546                   goto leave;
547                 }
548               rc = 0;
549             }
550         }
551
552       if (subject && !strcmp (issuer, subject))
553         {
554           if (gpgsm_check_cert_sig (subject_cert, subject_cert) )
555             {
556               log_error ("selfsigned certificate has a BAD signatures\n");
557               rc = gpg_error (depth? GPG_ERR_BAD_CERT_CHAIN
558                                    : GPG_ERR_BAD_CERT);
559               goto leave;
560             }
561           rc = allowed_ca (subject_cert, NULL);
562           if (rc)
563             goto leave;
564
565           rc = gpgsm_agent_istrusted (subject_cert);
566           if (!rc)
567             ;
568           else if (gpg_err_code (rc) == GPG_ERR_NOT_TRUSTED)
569             {
570               int rc2;
571
572               char *fpr = gpgsm_get_fingerprint_string (subject_cert,
573                                                         GCRY_MD_SHA1);
574               log_info (_("root certificate is not marked trusted\n"));
575               log_info (_("fingerprint=%s\n"), fpr? fpr : "?");
576               xfree (fpr);
577               rc2 = gpgsm_agent_marktrusted (subject_cert);
578               if (!rc2)
579                 {
580                   log_info (_("root certificate has now"
581                               " been marked as trusted\n"));
582                   rc = 0;
583                 }
584               else 
585                 {
586                   gpgsm_dump_cert ("issuer", subject_cert);
587                   log_info ("after checking the fingerprint, you may want "
588                             "to enter it manually into "
589                             "\"~/.gnupg-test/trustlist.txt\"\n");
590                 }
591             }
592           else 
593             {
594               log_error (_("checking the trust list failed: %s\n"),
595                          gpg_strerror (rc));
596             }
597           
598           break;  /* okay, a self-signed certicate is an end-point */
599         }
600       
601       depth++;
602       if (depth > maxdepth)
603         {
604           log_error (_("certificate chain too long\n"));
605           rc = gpg_error (GPG_ERR_BAD_CERT_CHAIN);
606           goto leave;
607         }
608
609       /* find the next cert up the tree */
610       keydb_search_reset (kh);
611       rc = find_up (kh, subject_cert, issuer);
612       if (rc)
613         {
614           if (rc == -1)
615             {
616               log_info ("issuer certificate (#/");
617               gpgsm_dump_string (issuer);
618               log_printf (") not found\n");
619             }
620           else
621             log_error ("failed to find issuer's certificate: rc=%d\n", rc);
622           rc = gpg_error (GPG_ERR_MISSING_CERT);
623           goto leave;
624         }
625
626       ksba_cert_release (issuer_cert); issuer_cert = NULL;
627       rc = keydb_get_cert (kh, &issuer_cert);
628       if (rc)
629         {
630           log_error ("failed to get cert: rc=%d\n", rc);
631           rc = gpg_error (GPG_ERR_GENERAL);
632           goto leave;
633         }
634
635       if (DBG_X509)
636         {
637           log_debug ("got issuer's certificate:\n");
638           gpgsm_dump_cert ("issuer", issuer_cert);
639         }
640
641       if (gpgsm_check_cert_sig (issuer_cert, subject_cert) )
642         {
643           log_error ("certificate has a BAD signatures\n");
644           rc = gpg_error (GPG_ERR_BAD_CERT_CHAIN);
645           goto leave;
646         }
647
648       {
649         int chainlen;
650         rc = allowed_ca (issuer_cert, &chainlen);
651         if (rc)
652           goto leave;
653         if (chainlen >= 0 && (depth - 1) > chainlen)
654           {
655             log_error (_("certificate chain longer than allowed by CA (%d)\n"),
656                        chainlen);
657             rc = gpg_error (GPG_ERR_BAD_CERT_CHAIN);
658             goto leave;
659           }
660       }
661
662       rc = gpgsm_cert_use_cert_p (issuer_cert);
663       if (rc)
664         {
665           char numbuf[50];
666           sprintf (numbuf, "%d", rc);
667           gpgsm_status2 (ctrl, STATUS_ERROR, "certcert.issuer.keyusage",
668                          numbuf, NULL);
669           rc = 0;
670         }
671
672       if (opt.verbose)
673         log_info ("certificate is good\n");
674       
675       keydb_search_reset (kh);
676       subject_cert = issuer_cert;
677       issuer_cert = NULL;
678     }
679
680   if (opt.no_policy_check)
681     log_info ("policies not checked due to --disable-policy-checks option\n");
682   if (opt.no_crl_check && !ctrl->use_ocsp)
683     log_info ("CRLs not checked due to --disable-crl-checks option\n");
684
685   if (!rc)
686     { /* If we encountered an error somewhere during the checks, set
687          the error code to the most critical one */
688       if (any_revoked)
689         rc = gpg_error (GPG_ERR_CERT_REVOKED);
690       else if (any_no_crl)
691         rc = gpg_error (GPG_ERR_NO_CRL_KNOWN);
692       else if (any_crl_too_old)
693         rc = gpg_error (GPG_ERR_CRL_TOO_OLD);
694       else if (any_no_policy_match)
695         rc = gpg_error (GPG_ERR_NO_POLICY_MATCH);
696       else if (any_expired)
697         rc = gpg_error (GPG_ERR_CERT_EXPIRED);
698     }
699   
700  leave:
701   if (r_exptime)
702     gnupg_copy_time (r_exptime, exptime);
703   xfree (issuer);
704   keydb_release (kh); 
705   ksba_cert_release (issuer_cert);
706   if (subject_cert != cert)
707     ksba_cert_release (subject_cert);
708   return rc;
709 }
710
711
712 /* Check that the given certificate is valid but DO NOT check any
713    constraints.  We assume that the issuers certificate is already in
714    the DB and that this one is valid; which it should be because it
715    has been checked using this function. */
716 int
717 gpgsm_basic_cert_check (KsbaCert cert)
718 {
719   int rc = 0;
720   char *issuer = NULL;
721   char *subject = NULL;
722   KEYDB_HANDLE kh = keydb_new (0);
723   KsbaCert issuer_cert = NULL;
724
725   if (opt.no_chain_validation)
726     {
727       log_info ("WARNING: bypassing basic certificate checks\n");
728       return 0;
729     }
730
731   if (!kh)
732     {
733       log_error (_("failed to allocated keyDB handle\n"));
734       rc = gpg_error (GPG_ERR_GENERAL);
735       goto leave;
736     }
737
738   issuer = ksba_cert_get_issuer (cert, 0);
739   subject = ksba_cert_get_subject (cert, 0);
740   if (!issuer)
741     {
742       log_error ("no issuer found in certificate\n");
743       rc = gpg_error (GPG_ERR_BAD_CERT);
744       goto leave;
745     }
746
747   if (subject && !strcmp (issuer, subject))
748     {
749       if (gpgsm_check_cert_sig (cert, cert) )
750         {
751           log_error ("selfsigned certificate has a BAD signatures\n");
752           rc = gpg_error (GPG_ERR_BAD_CERT);
753           goto leave;
754         }
755     }
756   else
757     {
758       /* find the next cert up the tree */
759       keydb_search_reset (kh);
760       rc = find_up (kh, cert, issuer);
761       if (rc)
762         {
763           if (rc == -1)
764             {
765               log_info ("issuer certificate (#/");
766               gpgsm_dump_string (issuer);
767               log_printf (") not found\n");
768             }
769           else
770             log_error ("failed to find issuer's certificate: rc=%d\n", rc);
771           rc = gpg_error (GPG_ERR_MISSING_CERT);
772           goto leave;
773         }
774       
775       ksba_cert_release (issuer_cert); issuer_cert = NULL;
776       rc = keydb_get_cert (kh, &issuer_cert);
777       if (rc)
778         {
779           log_error ("failed to get cert: rc=%d\n", rc);
780           rc = gpg_error (GPG_ERR_GENERAL);
781           goto leave;
782         }
783
784       if (gpgsm_check_cert_sig (issuer_cert, cert) )
785         {
786           log_error ("certificate has a BAD signatures\n");
787           rc = gpg_error (GPG_ERR_BAD_CERT);
788           goto leave;
789         }
790       if (opt.verbose)
791         log_info ("certificate is good\n");
792     }
793
794  leave:
795   xfree (issuer);
796   keydb_release (kh); 
797   ksba_cert_release (issuer_cert);
798   return rc;
799 }
800