Key generation and signing using the OpenPGP card does rudimentary work.
[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, time_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   time_t current_time = gnupg_get_time ();
419   time_t exptime = 0;
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   if (r_exptime)
427     *r_exptime = 0;
428
429   if (opt.no_chain_validation)
430     {
431       log_info ("WARNING: bypassing certificate chain validation\n");
432       return 0;
433     }
434   
435   if (!kh)
436     {
437       log_error (_("failed to allocated keyDB handle\n"));
438       rc = gpg_error (GPG_ERR_GENERAL);
439       goto leave;
440     }
441
442   if (DBG_X509)
443     gpgsm_dump_cert ("subject", cert);
444
445   subject_cert = cert;
446   maxdepth = 50;
447
448   for (;;)
449     {
450       xfree (issuer);
451       xfree (subject);
452       issuer = ksba_cert_get_issuer (subject_cert, 0);
453       subject = ksba_cert_get_subject (subject_cert, 0);
454
455       if (!issuer)
456         {
457           log_error ("no issuer found in certificate\n");
458           rc = gpg_error (GPG_ERR_BAD_CERT);
459           goto leave;
460         }
461
462       {
463         time_t not_before, not_after;
464
465         not_before = ksba_cert_get_validity (subject_cert, 0);
466         not_after = ksba_cert_get_validity (subject_cert, 1);
467         if (not_before == (time_t)(-1) || not_after == (time_t)(-1))
468           {
469             log_error ("certificate with invalid validity\n");
470             rc = gpg_error (GPG_ERR_BAD_CERT);
471             goto leave;
472           }
473
474         if (not_after)
475           {
476             if (!exptime)
477               exptime = not_after;
478             else if (not_after < exptime)
479               exptime = not_after;
480           }
481
482         if (not_before && current_time < not_before)
483           {
484             log_error ("certificate too young; valid from ");
485             gpgsm_dump_time (not_before);
486             log_printf ("\n");
487             rc = gpg_error (GPG_ERR_CERT_TOO_YOUNG);
488             goto leave;
489           }            
490         if (not_after && current_time > not_after)
491           {
492             log_error ("certificate has expired at ");
493             gpgsm_dump_time (not_after);
494             log_printf ("\n");
495             any_expired = 1;
496           }            
497       }
498
499       rc = unknown_criticals (subject_cert);
500       if (rc)
501         goto leave;
502
503       if (!opt.no_policy_check)
504         {
505           rc = check_cert_policy (subject_cert);
506           if (gpg_err_code (rc) == GPG_ERR_NO_POLICY_MATCH)
507             {
508               any_no_policy_match = 1;
509               rc = 1;
510             }
511           else if (rc)
512             goto leave;
513         }
514
515       if (!opt.no_crl_check)
516         {
517           rc = gpgsm_dirmngr_isvalid (subject_cert);
518           if (rc)
519             {
520               switch (rc)
521                 {
522                 case GPG_ERR_CERT_REVOKED:
523                   log_error (_("the certificate has been revoked\n"));
524                   any_revoked = 1;
525                   break;
526                 case GPG_ERR_NO_CRL_KNOWN:
527                   log_error (_("no CRL found for certificate\n"));
528                   any_no_crl = 1;
529                   break;
530                 case GPG_ERR_CRL_TOO_OLD:
531                   log_error (_("the available CRL is too old\n"));
532                   log_info (_("please make sure that the "
533                               "\"dirmngr\" is properly installed\n"));
534                   any_crl_too_old = 1;
535                   break;
536                 default:
537                   log_error (_("checking the CRL failed: %s\n"),
538                              gpg_strerror (rc));
539                   goto leave;
540                 }
541               rc = 0;
542             }
543         }
544
545       if (subject && !strcmp (issuer, subject))
546         {
547           if (gpgsm_check_cert_sig (subject_cert, subject_cert) )
548             {
549               log_error ("selfsigned certificate has a BAD signatures\n");
550               rc = gpg_error (depth? GPG_ERR_BAD_CERT_CHAIN
551                                    : GPG_ERR_BAD_CERT);
552               goto leave;
553             }
554           rc = allowed_ca (subject_cert, NULL);
555           if (rc)
556             goto leave;
557
558           rc = gpgsm_agent_istrusted (subject_cert);
559           if (!rc)
560             ;
561           else if (gpg_err_code (rc) == GPG_ERR_NOT_TRUSTED)
562             {
563               int rc2;
564
565               char *fpr = gpgsm_get_fingerprint_string (subject_cert,
566                                                         GCRY_MD_SHA1);
567               log_info (_("root certificate is not marked trusted\n"));
568               log_info (_("fingerprint=%s\n"), fpr? fpr : "?");
569               xfree (fpr);
570               rc2 = gpgsm_agent_marktrusted (subject_cert);
571               if (!rc2)
572                 {
573                   log_info (_("root certificate has now"
574                               " been marked as trusted\n"));
575                   rc = 0;
576                 }
577               else 
578                 {
579                   gpgsm_dump_cert ("issuer", subject_cert);
580                   log_info ("after checking the fingerprint, you may want "
581                             "to enter it manually into "
582                             "\"~/.gnupg-test/trustlist.txt\"\n");
583                 }
584             }
585           else 
586             {
587               log_error (_("checking the trust list failed: %s\n"),
588                          gpg_strerror (rc));
589             }
590           
591           break;  /* okay, a self-signed certicate is an end-point */
592         }
593       
594       depth++;
595       if (depth > maxdepth)
596         {
597           log_error (_("certificate chain too long\n"));
598           rc = gpg_error (GPG_ERR_BAD_CERT_CHAIN);
599           goto leave;
600         }
601
602       /* find the next cert up the tree */
603       keydb_search_reset (kh);
604       rc = find_up (kh, subject_cert, issuer);
605       if (rc)
606         {
607           if (rc == -1)
608             {
609               log_info ("issuer certificate (#/");
610               gpgsm_dump_string (issuer);
611               log_printf (") not found\n");
612             }
613           else
614             log_error ("failed to find issuer's certificate: rc=%d\n", rc);
615           rc = gpg_error (GPG_ERR_MISSING_CERT);
616           goto leave;
617         }
618
619       ksba_cert_release (issuer_cert); issuer_cert = NULL;
620       rc = keydb_get_cert (kh, &issuer_cert);
621       if (rc)
622         {
623           log_error ("failed to get cert: rc=%d\n", rc);
624           rc = gpg_error (GPG_ERR_GENERAL);
625           goto leave;
626         }
627
628       if (DBG_X509)
629         {
630           log_debug ("got issuer's certificate:\n");
631           gpgsm_dump_cert ("issuer", issuer_cert);
632         }
633
634       if (gpgsm_check_cert_sig (issuer_cert, subject_cert) )
635         {
636           log_error ("certificate has a BAD signatures\n");
637           rc = gpg_error (GPG_ERR_BAD_CERT_CHAIN);
638           goto leave;
639         }
640
641       {
642         int chainlen;
643         rc = allowed_ca (issuer_cert, &chainlen);
644         if (rc)
645           goto leave;
646         if (chainlen >= 0 && (depth - 1) > chainlen)
647           {
648             log_error (_("certificate chain longer than allowed by CA (%d)\n"),
649                        chainlen);
650             rc = gpg_error (GPG_ERR_BAD_CERT_CHAIN);
651             goto leave;
652           }
653       }
654
655       rc = gpgsm_cert_use_cert_p (issuer_cert);
656       if (rc)
657         {
658           char numbuf[50];
659           sprintf (numbuf, "%d", rc);
660           gpgsm_status2 (ctrl, STATUS_ERROR, "certcert.issuer.keyusage",
661                          numbuf, NULL);
662           rc = 0;
663         }
664
665       if (opt.verbose)
666         log_info ("certificate is good\n");
667       
668       keydb_search_reset (kh);
669       subject_cert = issuer_cert;
670       issuer_cert = NULL;
671     }
672
673   if (opt.no_policy_check)
674     log_info ("policies not checked due to --disable-policy-checks option\n");
675   if (opt.no_crl_check)
676     log_info ("CRLs not checked due to --disable-crl-checks option\n");
677
678   if (!rc)
679     { /* If we encountered an error somewhere during the checks, set
680          the error code to the most critical one */
681       if (any_revoked)
682         rc = gpg_error (GPG_ERR_CERT_REVOKED);
683       else if (any_no_crl)
684         rc = gpg_error (GPG_ERR_NO_CRL_KNOWN);
685       else if (any_crl_too_old)
686         rc = gpg_error (GPG_ERR_CRL_TOO_OLD);
687       else if (any_no_policy_match)
688         rc = gpg_error (GPG_ERR_NO_POLICY_MATCH);
689       else if (any_expired)
690         rc = gpg_error (GPG_ERR_CERT_EXPIRED);
691     }
692   
693  leave:
694   if (r_exptime)
695     *r_exptime = exptime;
696   xfree (issuer);
697   keydb_release (kh); 
698   ksba_cert_release (issuer_cert);
699   if (subject_cert != cert)
700     ksba_cert_release (subject_cert);
701   return rc;
702 }
703
704
705 /* Check that the given certificate is valid but DO NOT check any
706    constraints.  We assume that the issuers certificate is already in
707    the DB and that this one is valid; which it should be because it
708    has been checked using this function. */
709 int
710 gpgsm_basic_cert_check (KsbaCert cert)
711 {
712   int rc = 0;
713   char *issuer = NULL;
714   char *subject = NULL;
715   KEYDB_HANDLE kh = keydb_new (0);
716   KsbaCert issuer_cert = NULL;
717
718   if (opt.no_chain_validation)
719     {
720       log_info ("WARNING: bypassing basic certificate checks\n");
721       return 0;
722     }
723
724   if (!kh)
725     {
726       log_error (_("failed to allocated keyDB handle\n"));
727       rc = gpg_error (GPG_ERR_GENERAL);
728       goto leave;
729     }
730
731   issuer = ksba_cert_get_issuer (cert, 0);
732   subject = ksba_cert_get_subject (cert, 0);
733   if (!issuer)
734     {
735       log_error ("no issuer found in certificate\n");
736       rc = gpg_error (GPG_ERR_BAD_CERT);
737       goto leave;
738     }
739
740   if (subject && !strcmp (issuer, subject))
741     {
742       if (gpgsm_check_cert_sig (cert, cert) )
743         {
744           log_error ("selfsigned certificate has a BAD signatures\n");
745           rc = gpg_error (GPG_ERR_BAD_CERT);
746           goto leave;
747         }
748     }
749   else
750     {
751       /* find the next cert up the tree */
752       keydb_search_reset (kh);
753       rc = find_up (kh, cert, issuer);
754       if (rc)
755         {
756           if (rc == -1)
757             {
758               log_info ("issuer certificate (#/");
759               gpgsm_dump_string (issuer);
760               log_printf (") not found\n");
761             }
762           else
763             log_error ("failed to find issuer's certificate: rc=%d\n", rc);
764           rc = gpg_error (GPG_ERR_MISSING_CERT);
765           goto leave;
766         }
767       
768       ksba_cert_release (issuer_cert); issuer_cert = NULL;
769       rc = keydb_get_cert (kh, &issuer_cert);
770       if (rc)
771         {
772           log_error ("failed to get cert: rc=%d\n", rc);
773           rc = gpg_error (GPG_ERR_GENERAL);
774           goto leave;
775         }
776
777       if (gpgsm_check_cert_sig (issuer_cert, cert) )
778         {
779           log_error ("certificate has a BAD signatures\n");
780           rc = gpg_error (GPG_ERR_BAD_CERT);
781           goto leave;
782         }
783       if (opt.verbose)
784         log_info ("certificate is good\n");
785     }
786
787  leave:
788   xfree (issuer);
789   keydb_release (kh); 
790   ksba_cert_release (issuer_cert);
791   return rc;
792 }
793