Fixed compiler warning in invocation of crl_is_newer()
[strongswan.git] / src / pluto / crl.c
1 /* Support of X.509 certificate revocation lists (CRLs)
2 * Copyright (C) 2000-2009 Andreas Steffen
3 *
4 * HSR Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <dirent.h>
22 #include <time.h>
23 #include <sys/types.h>
24
25 #include <freeswan.h>
26
27 #include "constants.h"
28 #include "defs.h"
29 #include "log.h"
30 #include "x509.h"
31 #include "crl.h"
32 #include "ca.h"
33 #include "certs.h"
34 #include "keys.h"
35 #include "whack.h"
36 #include "fetch.h"
37 #include "builder.h"
38
39
40 /* chained lists of X.509 crls */
41
42 static x509crl_t *x509crls = NULL;
43
44 /**
45 * Get the X.509 CRL with a given issuer
46 */
47 static x509crl_t* get_x509crl(identification_t *issuer, chunk_t keyid)
48 {
49 x509crl_t *x509crl = x509crls;
50 x509crl_t *prev_crl = NULL;
51
52 while (x509crl != NULL)
53 {
54 certificate_t *cert_crl = x509crl->crl;
55 crl_t *crl = (crl_t*)cert_crl;
56 identification_t *crl_issuer = cert_crl->get_issuer(cert_crl);
57 chunk_t authKeyID = crl->get_authKeyIdentifier(crl);
58
59 if ((keyid.ptr && authKeyID.ptr)? same_keyid(keyid, authKeyID) :
60 issuer->equals(issuer, crl_issuer))
61 {
62 if (x509crl != x509crls)
63 {
64 /* bring the CRL up front */
65 prev_crl->next = x509crl->next;
66 x509crl->next = x509crls;
67 x509crls = x509crl;
68 }
69 return x509crl;
70 }
71 prev_crl = x509crl;
72 x509crl = x509crl->next;
73 }
74 return NULL;
75 }
76
77 /**
78 * Free the dynamic memory used to store CRLs
79 */
80 void free_crl(x509crl_t *crl)
81 {
82 DESTROY_IF(crl->crl);
83 crl->distributionPoints->destroy_function(crl->distributionPoints, free);
84 free(crl);
85 }
86
87 static void free_first_crl(void)
88 {
89 x509crl_t *crl = x509crls;
90
91 x509crls = crl->next;
92 free_crl(crl);
93 }
94
95 void free_crls(void)
96 {
97 lock_crl_list("free_crls");
98
99 while (x509crls != NULL)
100 {
101 free_first_crl();
102 }
103
104 unlock_crl_list("free_crls");
105 }
106
107 /**
108 * Insert X.509 CRL into chained list
109 */
110 bool insert_crl(x509crl_t *x509crl, char *crl_uri, bool cache_crl)
111 {
112 certificate_t *cert_crl = x509crl->crl;
113 crl_t *crl = (crl_t*)cert_crl;
114 identification_t *issuer = cert_crl->get_issuer(cert_crl);
115 chunk_t authKeyID = crl->get_authKeyIdentifier(crl);
116 cert_t *issuer_cert;
117 x509crl_t *oldcrl;
118 time_t now, nextUpdate;
119 bool valid_sig;
120
121 /* add distribution point */
122 add_distribution_point(x509crl->distributionPoints, crl_uri);
123
124 lock_authcert_list("insert_crl");
125
126 /* get the issuer cacert */
127 issuer_cert = get_authcert(issuer, authKeyID, X509_CA);
128 if (issuer_cert == NULL)
129 {
130 plog("crl issuer cacert not found");
131 free_crl(x509crl);
132 unlock_authcert_list("insert_crl");
133 return FALSE;
134 }
135 DBG(DBG_CONTROL,
136 DBG_log("crl issuer cacert found")
137 )
138
139 /* check the issuer's signature of the crl */
140 valid_sig = cert_crl->issued_by(cert_crl, issuer_cert->cert);
141 unlock_authcert_list("insert_crl");
142
143 if (!valid_sig)
144 {
145 free_crl(x509crl);
146 return FALSE;
147 }
148 DBG(DBG_CONTROL,
149 DBG_log("crl signature is valid")
150 )
151
152 /* note the current time */
153 time(&now);
154
155 lock_crl_list("insert_crl");
156 oldcrl = get_x509crl(issuer, authKeyID);
157
158 if (oldcrl != NULL)
159 {
160 certificate_t *old_cert_crl = oldcrl->crl;
161
162 if (crl_is_newer((crl_t*)cert_crl, (crl_t*)old_cert_crl))
163 {
164 /* keep any known CRL distribution points */
165 add_distribution_points(x509crl->distributionPoints,
166 oldcrl->distributionPoints);
167
168 /* now delete the old CRL */
169 free_first_crl();
170 DBG(DBG_CONTROL,
171 DBG_log("thisUpdate is newer - existing crl deleted")
172 )
173 }
174 else
175 {
176 unlock_crl_list("insert_crls");
177 DBG(DBG_CONTROL,
178 DBG_log("thisUpdate is not newer - existing crl not replaced");
179 )
180 free_crl(x509crl);
181 old_cert_crl->get_validity(old_cert_crl, &now, NULL, &nextUpdate);
182 return nextUpdate - now > 2*crl_check_interval;
183 }
184 }
185
186 /* insert new CRL */
187 x509crl->next = x509crls;
188 x509crls = x509crl;
189
190 unlock_crl_list("insert_crl");
191
192 /* If crl caching is enabled then the crl is saved locally.
193 * Only http or ldap URIs are cached but not local file URIs.
194 * The CRL's authorityKeyIdentifier is used as a unique filename
195 */
196 if (cache_crl && strncasecmp(crl_uri, "file", 4) != 0)
197 {
198 char buf[BUF_LEN];
199 chunk_t hex, encoding;
200
201 hex = chunk_to_hex(crl->get_authKeyIdentifier(crl), NULL, FALSE);
202 snprintf(buf, sizeof(buf), "%s/%s.crl", CRL_PATH, hex);
203 free(hex.ptr);
204
205 encoding = cert_crl->get_encoding(cert_crl);
206 chunk_write(encoding, buf, "crl", 022, TRUE);
207 free(encoding.ptr);
208 }
209
210 /* is the fetched crl valid? */
211 cert_crl->get_validity(cert_crl, &now, NULL, &nextUpdate);
212 return nextUpdate - now > 2*crl_check_interval;
213 }
214
215 /**
216 * Loads CRLs
217 */
218 void load_crls(void)
219 {
220 struct dirent **filelist;
221 u_char buf[BUF_LEN];
222 u_char *save_dir;
223 int n;
224
225 /* change directory to specified path */
226 save_dir = getcwd(buf, BUF_LEN);
227 if (chdir(CRL_PATH))
228 {
229 plog("Could not change to directory '%s'", CRL_PATH);
230 }
231 else
232 {
233 plog("Changing to directory '%s'", CRL_PATH);
234 n = scandir(CRL_PATH, &filelist, file_select, alphasort);
235
236 if (n < 0)
237 plog(" scandir() error");
238 else
239 {
240 while (n--)
241 {
242 char *filename = filelist[n]->d_name;
243 x509crl_t *x509crl;
244
245 x509crl = lib->creds->create(lib->creds, CRED_CERTIFICATE,
246 CERT_PLUTO_CRL,
247 BUILD_FROM_FILE, filename, BUILD_END);
248 if (x509crl)
249 {
250 char crl_uri[BUF_LEN];
251
252 plog(" loaded crl from '%s'", filename);
253 snprintf(crl_uri, BUF_LEN, "file://%s/%s", CRL_PATH, filename);
254 insert_crl(x509crl, crl_uri, FALSE);
255 }
256 free(filelist[n]);
257 }
258 free(filelist);
259 }
260 }
261 /* restore directory path */
262 ignore_result(chdir(save_dir));
263 }
264
265
266 /* Checks if the current certificate is revoked. It goes through the
267 * list of revoked certificates of the corresponding crl. Either the
268 * status CERT_GOOD or CERT_REVOKED is returned
269 */
270 static cert_status_t check_revocation(crl_t *crl, chunk_t cert_serial,
271 time_t *revocationDate,
272 crl_reason_t *revocationReason)
273 {
274 enumerator_t *enumerator;
275 cert_status_t status;
276 chunk_t serial;
277
278 DBG(DBG_CONTROL,
279 DBG_log("serial number: %#B", &cert_serial)
280 )
281 *revocationDate = UNDEFINED_TIME;
282 *revocationReason = CRL_REASON_UNSPECIFIED;
283 status = CERT_GOOD;
284
285 enumerator = crl->create_enumerator(crl);
286 while (enumerator->enumerate(enumerator, &serial,
287 revocationDate, revocationReason))
288 {
289 if (chunk_equals(serial, cert_serial))
290 {
291 status = CERT_REVOKED;
292 break;
293 }
294 }
295 enumerator->destroy(enumerator);
296 return status;
297 }
298
299 /*
300 * check if any crls are about to expire
301 */
302 void check_crls(void)
303 {
304 x509crl_t *x509crl;
305 time_t now, nextUpdate, time_left;
306
307 lock_crl_list("check_crls");
308 time(&now);
309 x509crl = x509crls;
310
311 while (x509crl != NULL)
312 {
313 certificate_t *cert_crl = x509crl->crl;
314 crl_t *crl = (crl_t*)cert_crl;
315 identification_t *issuer = cert_crl->get_issuer(cert_crl);
316 chunk_t authKeyID = crl->get_authKeyIdentifier(crl);
317
318 cert_crl->get_validity(cert_crl, &now, NULL, &nextUpdate);
319 time_left = nextUpdate - now;
320
321 DBG(DBG_CONTROL,
322 DBG_log("issuer: '%Y'", issuer);
323 if (authKeyID.ptr)
324 {
325 DBG_log("authkey: %#B", &authKeyID);
326 }
327 DBG_log("%ld seconds left", time_left)
328 )
329 if (time_left < 2*crl_check_interval)
330 {
331 fetch_req_t *req = build_crl_fetch_request(issuer, authKeyID,
332 x509crl->distributionPoints);
333 add_crl_fetch_request(req);
334 }
335 x509crl = x509crl->next;
336 }
337 unlock_crl_list("check_crls");
338 }
339
340 /*
341 * verify if a cert hasn't been revoked by a crl
342 */
343 cert_status_t verify_by_crl(cert_t *cert, time_t *until, time_t *revocationDate,
344 crl_reason_t *revocationReason)
345 {
346 certificate_t *certificate = cert->cert;
347 x509_t *x509 = (x509_t*)certificate;
348 identification_t *issuer = certificate->get_issuer(certificate);
349 chunk_t authKeyID = x509->get_authKeyIdentifier(x509);
350 x509crl_t *x509crl;
351 ca_info_t *ca;
352 enumerator_t *enumerator;
353 char *point;
354
355 ca = get_ca_info(issuer, authKeyID);
356
357 *revocationDate = UNDEFINED_TIME;
358 *revocationReason = CRL_REASON_UNSPECIFIED;
359
360 lock_crl_list("verify_by_crl");
361 x509crl = get_x509crl(issuer, authKeyID);
362
363 if (x509crl == NULL)
364 {
365 linked_list_t *crluris;
366
367 unlock_crl_list("verify_by_crl");
368 plog("crl not found");
369
370 crluris = linked_list_create();
371 if (ca)
372 {
373 add_distribution_points(crluris, ca->crluris);
374 }
375
376 enumerator = x509->create_crl_uri_enumerator(x509);
377 while (enumerator->enumerate(enumerator, &point))
378 {
379 add_distribution_point(crluris, point);
380 }
381 enumerator->destroy(enumerator);
382
383 if (crluris->get_count(crluris) > 0)
384 {
385 fetch_req_t *req;
386
387 req = build_crl_fetch_request(issuer, authKeyID, crluris);
388 crluris->destroy_function(crluris, free);
389 add_crl_fetch_request(req);
390 wake_fetch_thread("verify_by_crl");
391 return CERT_UNKNOWN;
392 }
393 else
394 {
395 crluris->destroy(crluris);
396 return CERT_UNDEFINED;
397 }
398 }
399 else
400 {
401 certificate_t *cert_crl = x509crl->crl;
402 crl_t *crl = (crl_t*)cert_crl;
403 chunk_t authKeyID = crl->get_authKeyIdentifier(crl);
404 cert_t *issuer_cert;
405 bool trusted, valid;
406
407 DBG(DBG_CONTROL,
408 DBG_log("crl found")
409 )
410
411 if (ca)
412 {
413 add_distribution_points(x509crl->distributionPoints, ca->crluris);
414 }
415
416 enumerator = x509->create_crl_uri_enumerator(x509);
417 while (enumerator->enumerate(enumerator, &point))
418 {
419 add_distribution_point(x509crl->distributionPoints, point);
420 }
421 enumerator->destroy(enumerator);
422
423 lock_authcert_list("verify_by_crl");
424
425 issuer_cert = get_authcert(issuer, authKeyID, X509_CA);
426 trusted = cert_crl->issued_by(cert_crl, issuer_cert->cert);
427
428 unlock_authcert_list("verify_by_crl");
429
430 if (trusted)
431 {
432 cert_status_t status;
433
434 DBG(DBG_CONTROL,
435 DBG_log("crl signature is valid")
436 )
437
438 /* return the expiration date */
439 valid = cert_crl->get_validity(cert_crl, NULL, NULL, until);
440
441 /* has the certificate been revoked? */
442 status = check_revocation(crl, x509->get_serial(x509), revocationDate
443 , revocationReason);
444
445 if (valid)
446 {
447 unlock_crl_list("verify_by_crl");
448 DBG(DBG_CONTROL,
449 DBG_log("crl is valid: until %T", until, FALSE)
450 )
451 }
452 else
453 {
454 fetch_req_t *req;
455
456 DBG(DBG_CONTROL,
457 DBG_log("crl is stale: since %T", until, FALSE)
458 )
459
460 /* try to fetch a crl update */
461 req = build_crl_fetch_request(issuer, authKeyID,
462 x509crl->distributionPoints);
463 unlock_crl_list("verify_by_crl");
464
465 add_crl_fetch_request(req);
466 wake_fetch_thread("verify_by_crl");
467 }
468 return status;
469 }
470 else
471 {
472 unlock_crl_list("verify_by_crl");
473 plog("crl signature is invalid");
474 return CERT_UNKNOWN;
475 }
476 }
477 }
478
479 /*
480 * list all X.509 crls in the chained list
481 */
482 void list_crls(bool utc, bool strict)
483 {
484 x509crl_t *x509crl;
485
486 lock_crl_list("list_crls");
487 x509crl = x509crls;
488
489 if (x509crl)
490 {
491 whack_log(RC_COMMENT, " ");
492 whack_log(RC_COMMENT, "List of X.509 CRLs:");
493 }
494
495 while (x509crl)
496 {
497 certificate_t *cert_crl = x509crl->crl;
498 crl_t *crl = (crl_t*)cert_crl;
499 chunk_t serial, authKeyID;
500 time_t thisUpdate, nextUpdate;
501 u_int revoked = 0;
502 enumerator_t *enumerator;
503
504 whack_log(RC_COMMENT, " ");
505 whack_log(RC_COMMENT, " issuer: \"%Y\"",
506 cert_crl->get_issuer(cert_crl));
507 serial = crl->get_serial(crl);
508 if (serial.ptr)
509 {
510 whack_log(RC_COMMENT, " serial: %#B", &serial);
511 }
512
513 /* count number of revoked certificates in CRL */
514 enumerator = crl->create_enumerator(crl);
515 while (enumerator->enumerate(enumerator, NULL, NULL, NULL))
516 {
517 revoked++;
518 }
519 enumerator->destroy(enumerator);
520 whack_log(RC_COMMENT, " revoked: %d certificates", revoked);
521
522 list_distribution_points(x509crl->distributionPoints);
523
524 cert_crl->get_validity(cert_crl, NULL, &thisUpdate, &nextUpdate);
525 whack_log(RC_COMMENT, " updates: this %T", &thisUpdate, utc);
526 whack_log(RC_COMMENT, " next %T %s", &nextUpdate, utc,
527 check_expiry(nextUpdate, CRL_WARNING_INTERVAL, strict));
528 authKeyID = crl->get_authKeyIdentifier(crl);
529 if (authKeyID.ptr)
530 {
531 whack_log(RC_COMMENT, " authkey: %#B", &authKeyID);
532 }
533
534 x509crl = x509crl->next;
535 }
536 unlock_crl_list("list_crls");
537 }
538