c8fb107d5e3917957aa618591629e7fcc401eedc
[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 if (cert_crl->get_encoding(cert_crl, CERT_ASN1_DER, &encoding))
206 {
207 chunk_write(encoding, buf, "crl", 022, TRUE);
208 free(encoding.ptr);
209 }
210 }
211
212 /* is the fetched crl valid? */
213 cert_crl->get_validity(cert_crl, &now, NULL, &nextUpdate);
214 return nextUpdate - now > 2*crl_check_interval;
215 }
216
217 /**
218 * Loads CRLs
219 */
220 void load_crls(void)
221 {
222 struct dirent **filelist;
223 u_char buf[BUF_LEN];
224 u_char *save_dir;
225 int n;
226
227 /* change directory to specified path */
228 save_dir = getcwd(buf, BUF_LEN);
229 if (chdir(CRL_PATH))
230 {
231 plog("Could not change to directory '%s'", CRL_PATH);
232 }
233 else
234 {
235 plog("Changing to directory '%s'", CRL_PATH);
236 n = scandir(CRL_PATH, &filelist, file_select, alphasort);
237
238 if (n < 0)
239 plog(" scandir() error");
240 else
241 {
242 while (n--)
243 {
244 char *filename = filelist[n]->d_name;
245 x509crl_t *x509crl;
246
247 x509crl = lib->creds->create(lib->creds, CRED_CERTIFICATE,
248 CERT_PLUTO_CRL,
249 BUILD_FROM_FILE, filename, BUILD_END);
250 if (x509crl)
251 {
252 char crl_uri[BUF_LEN];
253
254 plog(" loaded crl from '%s'", filename);
255 snprintf(crl_uri, BUF_LEN, "file://%s/%s", CRL_PATH, filename);
256 insert_crl(x509crl, crl_uri, FALSE);
257 }
258 free(filelist[n]);
259 }
260 free(filelist);
261 }
262 }
263 /* restore directory path */
264 ignore_result(chdir(save_dir));
265 }
266
267
268 /* Checks if the current certificate is revoked. It goes through the
269 * list of revoked certificates of the corresponding crl. Either the
270 * status CERT_GOOD or CERT_REVOKED is returned
271 */
272 static cert_status_t check_revocation(crl_t *crl, chunk_t cert_serial,
273 time_t *revocationDate,
274 crl_reason_t *revocationReason)
275 {
276 enumerator_t *enumerator;
277 cert_status_t status;
278 chunk_t serial;
279
280 DBG(DBG_CONTROL,
281 DBG_log("serial number: %#B", &cert_serial)
282 )
283 *revocationDate = UNDEFINED_TIME;
284 *revocationReason = CRL_REASON_UNSPECIFIED;
285 status = CERT_GOOD;
286
287 enumerator = crl->create_enumerator(crl);
288 while (enumerator->enumerate(enumerator, &serial,
289 revocationDate, revocationReason))
290 {
291 if (chunk_equals(serial, cert_serial))
292 {
293 status = CERT_REVOKED;
294 break;
295 }
296 }
297 enumerator->destroy(enumerator);
298 return status;
299 }
300
301 /*
302 * check if any crls are about to expire
303 */
304 void check_crls(void)
305 {
306 x509crl_t *x509crl;
307 time_t now, nextUpdate, time_left;
308
309 lock_crl_list("check_crls");
310 time(&now);
311 x509crl = x509crls;
312
313 while (x509crl != NULL)
314 {
315 certificate_t *cert_crl = x509crl->crl;
316 crl_t *crl = (crl_t*)cert_crl;
317 identification_t *issuer = cert_crl->get_issuer(cert_crl);
318 chunk_t authKeyID = crl->get_authKeyIdentifier(crl);
319
320 cert_crl->get_validity(cert_crl, &now, NULL, &nextUpdate);
321 time_left = nextUpdate - now;
322
323 DBG(DBG_CONTROL,
324 DBG_log("issuer: '%Y'", issuer);
325 if (authKeyID.ptr)
326 {
327 DBG_log("authkey: %#B", &authKeyID);
328 }
329 DBG_log("%ld seconds left", time_left)
330 )
331 if (time_left < 2*crl_check_interval)
332 {
333 fetch_req_t *req = build_crl_fetch_request(issuer, authKeyID,
334 x509crl->distributionPoints);
335 add_crl_fetch_request(req);
336 }
337 x509crl = x509crl->next;
338 }
339 unlock_crl_list("check_crls");
340 }
341
342 /*
343 * verify if a cert hasn't been revoked by a crl
344 */
345 cert_status_t verify_by_crl(cert_t *cert, time_t *until, time_t *revocationDate,
346 crl_reason_t *revocationReason)
347 {
348 certificate_t *certificate = cert->cert;
349 x509_t *x509 = (x509_t*)certificate;
350 identification_t *issuer = certificate->get_issuer(certificate);
351 chunk_t authKeyID = x509->get_authKeyIdentifier(x509);
352 x509crl_t *x509crl;
353 ca_info_t *ca;
354 enumerator_t *enumerator;
355 char *point;
356
357 ca = get_ca_info(issuer, authKeyID);
358
359 *revocationDate = UNDEFINED_TIME;
360 *revocationReason = CRL_REASON_UNSPECIFIED;
361
362 lock_crl_list("verify_by_crl");
363 x509crl = get_x509crl(issuer, authKeyID);
364
365 if (x509crl == NULL)
366 {
367 linked_list_t *crluris;
368
369 unlock_crl_list("verify_by_crl");
370 plog("crl not found");
371
372 crluris = linked_list_create();
373 if (ca)
374 {
375 add_distribution_points(crluris, ca->crluris);
376 }
377
378 enumerator = x509->create_crl_uri_enumerator(x509);
379 while (enumerator->enumerate(enumerator, &point))
380 {
381 add_distribution_point(crluris, point);
382 }
383 enumerator->destroy(enumerator);
384
385 if (crluris->get_count(crluris) > 0)
386 {
387 fetch_req_t *req;
388
389 req = build_crl_fetch_request(issuer, authKeyID, crluris);
390 crluris->destroy_function(crluris, free);
391 add_crl_fetch_request(req);
392 wake_fetch_thread("verify_by_crl");
393 return CERT_UNKNOWN;
394 }
395 else
396 {
397 crluris->destroy(crluris);
398 return CERT_UNDEFINED;
399 }
400 }
401 else
402 {
403 certificate_t *cert_crl = x509crl->crl;
404 crl_t *crl = (crl_t*)cert_crl;
405 chunk_t authKeyID = crl->get_authKeyIdentifier(crl);
406 cert_t *issuer_cert;
407 bool trusted, valid;
408
409 DBG(DBG_CONTROL,
410 DBG_log("crl found")
411 )
412
413 if (ca)
414 {
415 add_distribution_points(x509crl->distributionPoints, ca->crluris);
416 }
417
418 enumerator = x509->create_crl_uri_enumerator(x509);
419 while (enumerator->enumerate(enumerator, &point))
420 {
421 add_distribution_point(x509crl->distributionPoints, point);
422 }
423 enumerator->destroy(enumerator);
424
425 lock_authcert_list("verify_by_crl");
426
427 issuer_cert = get_authcert(issuer, authKeyID, X509_CA);
428 trusted = cert_crl->issued_by(cert_crl, issuer_cert->cert);
429
430 unlock_authcert_list("verify_by_crl");
431
432 if (trusted)
433 {
434 cert_status_t status;
435
436 DBG(DBG_CONTROL,
437 DBG_log("crl signature is valid")
438 )
439
440 /* return the expiration date */
441 valid = cert_crl->get_validity(cert_crl, NULL, NULL, until);
442
443 /* has the certificate been revoked? */
444 status = check_revocation(crl, x509->get_serial(x509), revocationDate
445 , revocationReason);
446
447 if (valid)
448 {
449 unlock_crl_list("verify_by_crl");
450 DBG(DBG_CONTROL,
451 DBG_log("crl is valid: until %T", until, FALSE)
452 )
453 }
454 else
455 {
456 fetch_req_t *req;
457
458 DBG(DBG_CONTROL,
459 DBG_log("crl is stale: since %T", until, FALSE)
460 )
461
462 /* try to fetch a crl update */
463 req = build_crl_fetch_request(issuer, authKeyID,
464 x509crl->distributionPoints);
465 unlock_crl_list("verify_by_crl");
466
467 add_crl_fetch_request(req);
468 wake_fetch_thread("verify_by_crl");
469 }
470 return status;
471 }
472 else
473 {
474 unlock_crl_list("verify_by_crl");
475 plog("crl signature is invalid");
476 return CERT_UNKNOWN;
477 }
478 }
479 }
480
481 /*
482 * list all X.509 crls in the chained list
483 */
484 void list_crls(bool utc, bool strict)
485 {
486 x509crl_t *x509crl;
487
488 lock_crl_list("list_crls");
489 x509crl = x509crls;
490
491 if (x509crl)
492 {
493 whack_log(RC_COMMENT, " ");
494 whack_log(RC_COMMENT, "List of X.509 CRLs:");
495 }
496
497 while (x509crl)
498 {
499 certificate_t *cert_crl = x509crl->crl;
500 crl_t *crl = (crl_t*)cert_crl;
501 chunk_t serial, authKeyID;
502 time_t thisUpdate, nextUpdate;
503 u_int revoked = 0;
504 enumerator_t *enumerator;
505
506 whack_log(RC_COMMENT, " ");
507 whack_log(RC_COMMENT, " issuer: \"%Y\"",
508 cert_crl->get_issuer(cert_crl));
509 serial = crl->get_serial(crl);
510 if (serial.ptr)
511 {
512 whack_log(RC_COMMENT, " serial: %#B", &serial);
513 }
514
515 /* count number of revoked certificates in CRL */
516 enumerator = crl->create_enumerator(crl);
517 while (enumerator->enumerate(enumerator, NULL, NULL, NULL))
518 {
519 revoked++;
520 }
521 enumerator->destroy(enumerator);
522 whack_log(RC_COMMENT, " revoked: %d certificates", revoked);
523
524 list_distribution_points(x509crl->distributionPoints);
525
526 cert_crl->get_validity(cert_crl, NULL, &thisUpdate, &nextUpdate);
527 whack_log(RC_COMMENT, " updates: this %T", &thisUpdate, utc);
528 whack_log(RC_COMMENT, " next %T %s", &nextUpdate, utc,
529 check_expiry(nextUpdate, CRL_WARNING_INTERVAL, strict));
530 authKeyID = crl->get_authKeyIdentifier(crl);
531 if (authKeyID.ptr)
532 {
533 whack_log(RC_COMMENT, " authkey: %#B", &authKeyID);
534 }
535
536 x509crl = x509crl->next;
537 }
538 unlock_crl_list("list_crls");
539 }
540