* certpath.c (gpgsm_validate_path): Print the DN of a missing issuer.
[gnupg.git] / sm / certchain.c
1 /* certpath.c - path validation
2  *      Copyright (C) 2001 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 <gcrypt.h>
31 #include <ksba.h>
32
33 #include "gpgsm.h"
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 = GNUPG_Unsupported_Certificate;
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 *pathlen)
72 {
73   KsbaError err;
74   int flag;
75
76   err = ksba_cert_is_ca (cert, &flag, pathlen);
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 GNUPG_Bad_CA_Certificate;
83     }
84   return 0;
85 }
86
87
88 int
89 gpgsm_validate_path (KsbaCert cert)
90 {
91   int rc = 0, depth = 0, maxdepth;
92   char *issuer = NULL;
93   char *subject = NULL;
94   KEYDB_HANDLE kh = keydb_new (0);
95   KsbaCert subject_cert = NULL, issuer_cert = NULL;
96   time_t current_time = time (NULL);
97
98   if (!kh)
99     {
100       log_error (_("failed to allocated keyDB handle\n"));
101       rc = GNUPG_General_Error;
102       goto leave;
103     }
104
105   if (DBG_X509)
106     gpgsm_dump_cert ("subject", cert);
107
108   subject_cert = cert;
109   maxdepth = 50;
110
111   for (;;)
112     {
113       xfree (issuer);
114       xfree (subject);
115       issuer = ksba_cert_get_issuer (subject_cert, 0);
116       subject = ksba_cert_get_subject (subject_cert, 0);
117
118       if (!issuer)
119         {
120           log_error ("no issuer found in certificate\n");
121           rc = GNUPG_Bad_Certificate;
122           goto leave;
123         }
124
125       {
126         time_t not_before, not_after;
127
128         not_before = ksba_cert_get_validity (subject_cert, 0);
129         not_after = ksba_cert_get_validity (subject_cert, 1);
130         if (not_before == (time_t)(-1) || not_after == (time_t)(-1))
131           {
132             log_error ("certificate with invalid validity\n");
133             rc = GNUPG_Bad_Certificate;
134             goto leave;
135           }
136
137         if (current_time < not_before)
138           {
139             log_error ("certificate to young; valid from ");
140             gpgsm_dump_time (not_before);
141             log_printf ("\n");
142             rc = GNUPG_Certificate_Too_Young;
143             goto leave;
144           }            
145         if (current_time > not_after)
146           {
147             log_error ("certificate has expired at ");
148             gpgsm_dump_time (not_after);
149             log_printf ("\n");
150             rc = GNUPG_Certificate_Expired;
151             goto leave;
152           }            
153       }
154
155       rc = unknown_criticals (subject_cert);
156       if (rc)
157         goto leave;
158         
159       if (!opt.no_crl_check)
160         {
161           rc = gpgsm_dirmngr_isvalid (subject_cert);
162           if (rc)
163             {
164               switch (rc)
165                 {
166                 case GNUPG_Certificate_Revoked:
167                   log_error (_("the certificate has been revoked\n"));
168                   break;
169                 case GNUPG_No_CRL_Known:
170                   log_error (_("no CRL found for certificate\n"));
171                   break;
172                 case GNUPG_CRL_Too_Old:
173                   log_error (_("the available CRL is too old\n"));
174                   log_info (_("please make sure that the "
175                               "\"dirmngr\" is properly installed\n"));
176                   break;
177                 default:
178                   log_error (_("checking the CRL failed: %s\n"),
179                              gnupg_strerror (rc));
180                   break;
181                 }
182               goto leave;
183             }
184         }
185
186       if (subject && !strcmp (issuer, subject))
187         {
188           if (gpgsm_check_cert_sig (subject_cert, subject_cert) )
189             {
190               log_error ("selfsigned certificate has a BAD signatures\n");
191               rc = depth? GNUPG_Bad_Certificate_Path : GNUPG_Bad_Certificate;
192               goto leave;
193             }
194           rc = allowed_ca (subject_cert, NULL);
195           if (rc)
196             goto leave;
197
198           rc = gpgsm_agent_istrusted (subject_cert);
199           if (!rc)
200             ;
201           else if (rc == GNUPG_Not_Trusted)
202             {
203               char *fpr = gpgsm_get_fingerprint_string (subject_cert,
204                                                         GCRY_MD_SHA1);
205               log_error (_("root certificate is not marked trusted\n"));
206               log_info (_("fingerprint=%s\n"), fpr? fpr : "?");
207               xfree (fpr);
208               /* fixme: print a note while we have not yet the code to
209                  ask whether the cert should be entered into the trust
210                  list */
211               gpgsm_dump_cert ("issuer", subject_cert);
212               log_info ("after checking the fingerprint, you may want "
213                         "to enter it into \"~/.gnupg-test/trustlist.txt\"\n");
214             }
215           else 
216             {
217               log_error (_("checking the trust list failed: %s\n"),
218                          gnupg_strerror (rc));
219             }
220           
221           break;  /* okay, a self-signed certicate is an end-point */
222         }
223       
224       depth++;
225       if (depth > maxdepth)
226         {
227           log_error (_("certificate path too long\n"));
228           rc = GNUPG_Bad_Certificate_Path;
229           goto leave;
230         }
231
232       /* find the next cert up the tree */
233       keydb_search_reset (kh);
234       rc = keydb_search_subject (kh, issuer);
235       if (rc)
236         {
237           if (rc == -1)
238             {
239               log_info ("issuer certificate (");
240               gpgsm_dump_string (issuer);
241               log_printf (") not found\n");
242             }
243           else
244             log_error ("failed to find issuer's certificate: rc=%d\n", rc);
245           rc = GNUPG_Missing_Certificate;
246           goto leave;
247         }
248
249       ksba_cert_release (issuer_cert); issuer_cert = NULL;
250       rc = keydb_get_cert (kh, &issuer_cert);
251       if (rc)
252         {
253           log_error ("failed to get cert: rc=%d\n", rc);
254           rc = GNUPG_General_Error;
255           goto leave;
256         }
257
258       if (DBG_X509)
259         {
260           log_debug ("got issuer's certificate:\n");
261           gpgsm_dump_cert ("issuer", issuer_cert);
262         }
263
264       if (gpgsm_check_cert_sig (issuer_cert, subject_cert) )
265         {
266           log_error ("certificate has a BAD signatures\n");
267           rc = GNUPG_Bad_Certificate_Path;
268           goto leave;
269         }
270
271       {
272         int pathlen;
273         rc = allowed_ca (issuer_cert, &pathlen);
274         if (rc)
275           goto leave;
276         if (pathlen >= 0 && (depth - 1) > pathlen)
277           {
278             log_error (_("certificate path longer than allowed by CA (%d)\n"),
279                        pathlen);
280             rc = GNUPG_Bad_Certificate_Path;
281             goto leave;
282           }
283       }
284
285       log_info ("certificate is good\n");
286       
287       keydb_search_reset (kh);
288       subject_cert = issuer_cert;
289       issuer_cert = NULL;
290     }
291
292   if (opt.no_crl_check)
293     log_info ("CRL was not checked due to --no-crl-cechk option\n");
294
295   
296  leave:
297   xfree (issuer);
298   keydb_release (kh); 
299   ksba_cert_release (issuer_cert);
300   if (subject_cert != cert)
301     ksba_cert_release (subject_cert);
302   return rc;
303 }
304
305
306 /* Check that the given certificate is valid but DO NOT check any
307    constraints.  We assume that the issuers certificate is already in
308    the DB and that this one is valid; which it should be because it
309    has been checked using this function. */
310 int
311 gpgsm_basic_cert_check (KsbaCert cert)
312 {
313   int rc = 0;
314   char *issuer = NULL;
315   char *subject = NULL;
316   KEYDB_HANDLE kh = keydb_new (0);
317   KsbaCert issuer_cert = NULL;
318
319   if (!kh)
320     {
321       log_error (_("failed to allocated keyDB handle\n"));
322       rc = GNUPG_General_Error;
323       goto leave;
324     }
325
326   issuer = ksba_cert_get_issuer (cert, 0);
327   subject = ksba_cert_get_subject (cert, 0);
328   if (!issuer)
329     {
330       if (DBG_X509)
331         log_debug ("ERROR: issuer missing\n");
332       rc = GNUPG_Bad_Certificate;
333       goto leave;
334     }
335
336   if (subject && !strcmp (issuer, subject))
337     {
338       if (gpgsm_check_cert_sig (cert, cert) )
339         {
340           log_error ("selfsigned certificate has a BAD signatures\n");
341           rc = GNUPG_Bad_Certificate;
342           goto leave;
343         }
344     }
345   else
346     {
347       /* find the next cert up the tree */
348       keydb_search_reset (kh);
349       rc = keydb_search_subject (kh, issuer);
350       if (rc)
351         {
352           if (rc == -1)
353             {
354               log_info ("issuer certificate (");
355               gpgsm_dump_string (issuer);
356               log_printf (") not found\n");
357             }
358           else
359             log_error ("failed to find issuer's certificate: rc=%d\n", rc);
360           rc = GNUPG_Missing_Certificate;
361           goto leave;
362         }
363       
364       ksba_cert_release (issuer_cert); issuer_cert = NULL;
365       rc = keydb_get_cert (kh, &issuer_cert);
366       if (rc)
367         {
368           log_error ("failed to get cert: rc=%d\n", rc);
369           rc = GNUPG_General_Error;
370           goto leave;
371         }
372
373       if (gpgsm_check_cert_sig (issuer_cert, cert) )
374         {
375           log_error ("certificate has a BAD signatures\n");
376           rc = GNUPG_Bad_Certificate;
377           goto leave;
378         }
379       if (opt.verbose)
380         log_info ("certificate is good\n");
381     }
382
383  leave:
384   xfree (issuer);
385   keydb_release (kh); 
386   ksba_cert_release (issuer_cert);
387   return rc;
388 }
389