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