* gpgsm.c (main): New option --debug-ignore-expiration.
[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 static int
70 unknown_criticals (ksba_cert_t cert, int listmode, FILE *fp)
71 {
72   static const char *known[] = {
73     "2.5.29.15", /* keyUsage */
74     "2.5.29.19", /* basic Constraints */
75     "2.5.29.32", /* certificatePolicies */
76     "2.5.29.37", /* extendedKeyUsage - handled by certlist.c */
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 (opt.ignore_expiration?0:1, lm, fp,
554                      _("certificate has expired"));
555             if (!lm)
556               {
557                 log_info ("(expired at ");
558                 gpgsm_dump_time (not_after);
559                 log_printf (")\n");
560               }
561             if (opt.ignore_expiration)
562                 log_info ("WARNING: ignoring expiration\n");
563             else
564               any_expired = 1;
565           }            
566       }
567
568       rc = unknown_criticals (subject_cert, listmode, fp);
569       if (rc)
570         goto leave;
571
572       if (!opt.no_policy_check)
573         {
574           rc = check_cert_policy (subject_cert, listmode, fp);
575           if (gpg_err_code (rc) == GPG_ERR_NO_POLICY_MATCH)
576             {
577               any_no_policy_match = 1;
578               rc = 1;
579             }
580           else if (rc)
581             goto leave;
582         }
583
584       if (!opt.no_crl_check || ctrl->use_ocsp)
585         {
586           rc = gpgsm_dirmngr_isvalid (subject_cert, ctrl->use_ocsp);
587           if (rc)
588             {
589               /* Fixme: We should change the wording because we may
590                  have used OCSP. */
591               switch (gpg_err_code (rc))
592                 {
593                 case GPG_ERR_CERT_REVOKED:
594                   do_list (1, lm, fp, _("certificate has been revoked"));
595                   any_revoked = 1;
596                   /* Store that in the keybox so that key listings are
597                      able to return the revoked flag.  We don't care
598                      about error, though. */
599                   keydb_set_cert_flags (subject_cert, KEYBOX_FLAG_VALIDITY, 0,
600                                         VALIDITY_REVOKED);
601                   break;
602                 case GPG_ERR_NO_CRL_KNOWN:
603                   do_list (1, lm, fp, _("no CRL found for certificate"));
604                   any_no_crl = 1;
605                   break;
606                 case GPG_ERR_CRL_TOO_OLD:
607                   do_list (1, lm, fp, _("the available CRL is too old"));
608                   if (!lm)
609                     log_info (_("please make sure that the "
610                                 "\"dirmngr\" is properly installed\n"));
611                   any_crl_too_old = 1;
612                   break;
613                 default:
614                   do_list (1, lm, fp, _("checking the CRL failed: %s"),
615                            gpg_strerror (rc));
616                   goto leave;
617                 }
618               rc = 0;
619             }
620         }
621
622       if (subject && !strcmp (issuer, subject))
623         {
624           if (gpgsm_check_cert_sig (subject_cert, subject_cert) )
625             {
626               do_list (1, lm, fp,
627                        _("selfsigned certificate has a BAD signature"));
628               rc = gpg_error (depth? GPG_ERR_BAD_CERT_CHAIN
629                                    : GPG_ERR_BAD_CERT);
630               goto leave;
631             }
632           rc = allowed_ca (subject_cert, NULL, listmode, fp);
633           if (rc)
634             goto leave;
635
636           rc = gpgsm_agent_istrusted (subject_cert);
637           if (!rc)
638             ;
639           else if (gpg_err_code (rc) == GPG_ERR_NOT_TRUSTED)
640             {
641               do_list (0, lm, fp, _("root certificate is not marked trusted"));
642               if (!lm)
643                 {
644                   int rc2;
645                   char *fpr = gpgsm_get_fingerprint_string (subject_cert,
646                                                             GCRY_MD_SHA1);
647                   log_info (_("fingerprint=%s\n"), fpr? fpr : "?");
648                   xfree (fpr);
649                   rc2 = gpgsm_agent_marktrusted (subject_cert);
650                   if (!rc2)
651                     {
652                       log_info (_("root certificate has now"
653                                   " been marked as trusted\n"));
654                       rc = 0;
655                     }
656                   else 
657                     {
658                       gpgsm_dump_cert ("issuer", subject_cert);
659                       log_info ("after checking the fingerprint, you may want "
660                                 "to add it manually to the list of trusted "
661                                 "certificates.\n");
662                     }
663                 }
664             }
665           else 
666             {
667               log_error (_("checking the trust list failed: %s\n"),
668                          gpg_strerror (rc));
669             }
670           
671           break;  /* okay, a self-signed certicate is an end-point */
672         }
673       
674       depth++;
675       if (depth > maxdepth)
676         {
677           do_list (1, lm, fp, _("certificate chain too long\n"));
678           rc = gpg_error (GPG_ERR_BAD_CERT_CHAIN);
679           goto leave;
680         }
681
682       /* find the next cert up the tree */
683       keydb_search_reset (kh);
684       rc = find_up (kh, subject_cert, issuer, 0);
685       if (rc)
686         {
687           if (rc == -1)
688             {
689               do_list (0, lm, fp, _("issuer certificate not found"));
690               if (!lm)
691                 {
692                   log_info ("issuer certificate: #/");
693                   gpgsm_dump_string (issuer);
694                   log_printf ("\n");
695                 }
696             }
697           else
698             log_error ("failed to find issuer's certificate: rc=%d\n", rc);
699           rc = gpg_error (GPG_ERR_MISSING_CERT);
700           goto leave;
701         }
702
703     try_another_cert:
704       ksba_cert_release (issuer_cert); issuer_cert = NULL;
705       rc = keydb_get_cert (kh, &issuer_cert);
706       if (rc)
707         {
708           log_error ("failed to get cert: rc=%d\n", rc);
709           rc = gpg_error (GPG_ERR_GENERAL);
710           goto leave;
711         }
712
713       if (DBG_X509)
714         {
715           log_debug ("got issuer's certificate:\n");
716           gpgsm_dump_cert ("issuer", issuer_cert);
717         }
718
719       rc = gpgsm_check_cert_sig (issuer_cert, subject_cert);
720       if (rc)
721         {
722           do_list (0, lm, fp, _("certificate has a BAD signature"));
723           if (gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE)
724             {
725               rc = find_up (kh, subject_cert, issuer, 1);
726               if (!rc)
727                 {
728                   do_list (0, lm, fp, _("found another possible matching "
729                                         "CA certificate - trying again"));
730                   goto try_another_cert;
731                 }
732             }
733
734           /* We give a more descriptive error code than the one
735              returned from the signature checking. */
736           rc = gpg_error (GPG_ERR_BAD_CERT_CHAIN);
737           goto leave;
738         }
739
740       {
741         int chainlen;
742         rc = allowed_ca (issuer_cert, &chainlen, listmode, fp);
743         if (rc)
744           goto leave;
745         if (chainlen >= 0 && (depth - 1) > chainlen)
746           {
747             do_list (1, lm, fp,
748                      _("certificate chain longer than allowed by CA (%d)"),
749                      chainlen);
750             rc = gpg_error (GPG_ERR_BAD_CERT_CHAIN);
751             goto leave;
752           }
753       }
754
755       if (!listmode)
756         {
757           rc = gpgsm_cert_use_cert_p (issuer_cert);
758           if (rc)
759             {
760               char numbuf[50];
761               sprintf (numbuf, "%d", rc);
762               gpgsm_status2 (ctrl, STATUS_ERROR, "certcert.issuer.keyusage",
763                              numbuf, NULL);
764               rc = 0;
765             }
766         }
767
768       if (opt.verbose && !listmode)
769         log_info ("certificate is good\n");
770       
771       keydb_search_reset (kh);
772       subject_cert = issuer_cert;
773       issuer_cert = NULL;
774     }
775
776   if (!listmode)
777     {
778       if (opt.no_policy_check)
779         log_info ("policies not checked due to %s option\n",
780                   "--disable-policy-checks");
781       if (opt.no_crl_check && !ctrl->use_ocsp)
782         log_info ("CRLs not checked due to %s option\n",
783                   "--disable-crl-checks");
784     }
785
786   if (!rc)
787     { /* If we encountered an error somewhere during the checks, set
788          the error code to the most critical one */
789       if (any_revoked)
790         rc = gpg_error (GPG_ERR_CERT_REVOKED);
791       else if (any_no_crl)
792         rc = gpg_error (GPG_ERR_NO_CRL_KNOWN);
793       else if (any_crl_too_old)
794         rc = gpg_error (GPG_ERR_CRL_TOO_OLD);
795       else if (any_no_policy_match)
796         rc = gpg_error (GPG_ERR_NO_POLICY_MATCH);
797       else if (any_expired)
798         rc = gpg_error (GPG_ERR_CERT_EXPIRED);
799     }
800   
801  leave:
802   if (r_exptime)
803     gnupg_copy_time (r_exptime, exptime);
804   xfree (issuer);
805   keydb_release (kh); 
806   ksba_cert_release (issuer_cert);
807   if (subject_cert != cert)
808     ksba_cert_release (subject_cert);
809   return rc;
810 }
811
812
813 /* Check that the given certificate is valid but DO NOT check any
814    constraints.  We assume that the issuers certificate is already in
815    the DB and that this one is valid; which it should be because it
816    has been checked using this function. */
817 int
818 gpgsm_basic_cert_check (ksba_cert_t cert)
819 {
820   int rc = 0;
821   char *issuer = NULL;
822   char *subject = NULL;
823   KEYDB_HANDLE kh = keydb_new (0);
824   ksba_cert_t issuer_cert = NULL;
825   
826   if (opt.no_chain_validation)
827     {
828       log_info ("WARNING: bypassing basic certificate checks\n");
829       return 0;
830     }
831
832   if (!kh)
833     {
834       log_error (_("failed to allocated keyDB handle\n"));
835       rc = gpg_error (GPG_ERR_GENERAL);
836       goto leave;
837     }
838
839   issuer = ksba_cert_get_issuer (cert, 0);
840   subject = ksba_cert_get_subject (cert, 0);
841   if (!issuer)
842     {
843       log_error ("no issuer found in certificate\n");
844       rc = gpg_error (GPG_ERR_BAD_CERT);
845       goto leave;
846     }
847
848   if (subject && !strcmp (issuer, subject))
849     {
850       if (gpgsm_check_cert_sig (cert, cert) )
851         {
852           log_error ("selfsigned certificate has a BAD signature\n");
853           rc = gpg_error (GPG_ERR_BAD_CERT);
854           goto leave;
855         }
856     }
857   else
858     {
859       /* find the next cert up the tree */
860       keydb_search_reset (kh);
861       rc = find_up (kh, cert, issuer, 0);
862       if (rc)
863         {
864           if (rc == -1)
865             {
866               log_info ("issuer certificate (#/");
867               gpgsm_dump_string (issuer);
868               log_printf (") not found\n");
869             }
870           else
871             log_error ("failed to find issuer's certificate: rc=%d\n", rc);
872           rc = gpg_error (GPG_ERR_MISSING_CERT);
873           goto leave;
874         }
875       
876       ksba_cert_release (issuer_cert); issuer_cert = NULL;
877       rc = keydb_get_cert (kh, &issuer_cert);
878       if (rc)
879         {
880           log_error ("failed to get cert: rc=%d\n", rc);
881           rc = gpg_error (GPG_ERR_GENERAL);
882           goto leave;
883         }
884
885       if (gpgsm_check_cert_sig (issuer_cert, cert) )
886         {
887           log_error ("certificate has a BAD signature\n");
888           rc = gpg_error (GPG_ERR_BAD_CERT);
889           goto leave;
890         }
891       if (opt.verbose)
892         log_info ("certificate is good\n");
893     }
894
895  leave:
896   xfree (issuer);
897   keydb_release (kh); 
898   ksba_cert_release (issuer_cert);
899   return rc;
900 }
901