revocation: Make sure issuer of fetched CRL matches that of the certificate
[strongswan.git] / src / libstrongswan / plugins / revocation / revocation_validator.c
1 /*
2 * Copyright (C) 2010 Martin Willi
3 * Copyright (C) 2010 revosec AG
4 * Copyright (C) 2009 Andreas Steffen
5 * Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include "revocation_validator.h"
19
20 #include <utils/debug.h>
21 #include <credentials/certificates/x509.h>
22 #include <credentials/certificates/crl.h>
23 #include <credentials/certificates/ocsp_request.h>
24 #include <credentials/certificates/ocsp_response.h>
25 #include <credentials/sets/ocsp_response_wrapper.h>
26 #include <selectors/traffic_selector.h>
27
28 typedef struct private_revocation_validator_t private_revocation_validator_t;
29
30 /**
31 * Private data of an revocation_validator_t object.
32 */
33 struct private_revocation_validator_t {
34
35 /**
36 * Public revocation_validator_t interface.
37 */
38 revocation_validator_t public;
39
40 /**
41 * Enable OCSP validation
42 */
43 bool enable_ocsp;
44
45 /**
46 * Enable CRL validation
47 */
48 bool enable_crl;
49
50 };
51
52 /**
53 * Do an OCSP request
54 */
55 static certificate_t *fetch_ocsp(char *url, certificate_t *subject,
56 certificate_t *issuer)
57 {
58 certificate_t *request, *response;
59 chunk_t send, receive;
60
61 /* TODO: requestor name, signature */
62 request = lib->creds->create(lib->creds,
63 CRED_CERTIFICATE, CERT_X509_OCSP_REQUEST,
64 BUILD_CA_CERT, issuer,
65 BUILD_CERT, subject, BUILD_END);
66 if (!request)
67 {
68 DBG1(DBG_CFG, "generating ocsp request failed");
69 return NULL;
70 }
71
72 if (!request->get_encoding(request, CERT_ASN1_DER, &send))
73 {
74 DBG1(DBG_CFG, "encoding ocsp request failed");
75 request->destroy(request);
76 return NULL;
77 }
78 request->destroy(request);
79
80 DBG1(DBG_CFG, " requesting ocsp status from '%s' ...", url);
81 if (lib->fetcher->fetch(lib->fetcher, url, &receive,
82 FETCH_REQUEST_DATA, send,
83 FETCH_REQUEST_TYPE, "application/ocsp-request",
84 FETCH_END) != SUCCESS)
85 {
86 DBG1(DBG_CFG, "ocsp request to %s failed", url);
87 chunk_free(&send);
88 return NULL;
89 }
90 chunk_free(&send);
91
92 response = lib->creds->create(lib->creds,
93 CRED_CERTIFICATE, CERT_X509_OCSP_RESPONSE,
94 BUILD_BLOB_ASN1_DER, receive, BUILD_END);
95 chunk_free(&receive);
96 if (!response)
97 {
98 DBG1(DBG_CFG, "parsing ocsp response failed");
99 return NULL;
100 }
101 return response;
102 }
103
104 /**
105 * check the signature of an OCSP response
106 */
107 static bool verify_ocsp(ocsp_response_t *response, certificate_t *ca)
108 {
109 certificate_t *issuer, *subject;
110 identification_t *responder;
111 ocsp_response_wrapper_t *wrapper;
112 enumerator_t *enumerator;
113 x509_t *x509;
114 bool verified = FALSE, found = FALSE;
115
116 wrapper = ocsp_response_wrapper_create((ocsp_response_t*)response);
117 lib->credmgr->add_local_set(lib->credmgr, &wrapper->set, FALSE);
118
119 subject = &response->certificate;
120 responder = subject->get_issuer(subject);
121
122 /* check OCSP response using CA or directly delegated OCSP signer */
123 enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr, CERT_X509,
124 KEY_ANY, responder, FALSE);
125 while (enumerator->enumerate(enumerator, &issuer))
126 {
127 x509 = (x509_t*)issuer;
128 if (!issuer->get_validity(issuer, NULL, NULL, NULL))
129 { /* OCSP signer currently invalid */
130 continue;
131 }
132 if (!ca->equals(ca, issuer))
133 { /* delegated OCSP signer? */
134 if (!lib->credmgr->issued_by(lib->credmgr, issuer, ca, NULL))
135 { /* OCSP response not signed by CA, nor delegated OCSP signer */
136 continue;
137 }
138 if (!(x509->get_flags(x509) & X509_OCSP_SIGNER))
139 { /* delegated OCSP signer does not have OCSP signer flag */
140 continue;
141 }
142 }
143 found = TRUE;
144 if (lib->credmgr->issued_by(lib->credmgr, subject, issuer, NULL))
145 {
146 DBG1(DBG_CFG, " ocsp response correctly signed by \"%Y\"",
147 issuer->get_subject(issuer));
148 verified = TRUE;
149 break;
150 }
151 DBG1(DBG_CFG, "ocsp response verification failed, "
152 "invalid signature");
153 }
154 enumerator->destroy(enumerator);
155
156 if (!verified)
157 {
158 /* as fallback, use any locally installed OCSP signer certificate */
159 enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
160 CERT_X509, KEY_ANY, responder, TRUE);
161 while (enumerator->enumerate(enumerator, &issuer))
162 {
163 x509 = (x509_t*)issuer;
164 /* while issued_by() accepts both OCSP signer or CA basic
165 * constraint flags to verify OCSP responses, unrelated but trusted
166 * OCSP signers must explicitly have the OCSP signer flag set. */
167 if ((x509->get_flags(x509) & X509_OCSP_SIGNER) &&
168 issuer->get_validity(issuer, NULL, NULL, NULL))
169 {
170 found = TRUE;
171 if (lib->credmgr->issued_by(lib->credmgr, subject, issuer, NULL))
172 {
173 DBG1(DBG_CFG, " ocsp response correctly signed by \"%Y\"",
174 issuer->get_subject(issuer));
175 verified = TRUE;
176 break;
177 }
178 DBG1(DBG_CFG, "ocsp response verification failed, "
179 "invalid signature");
180 }
181 }
182 enumerator->destroy(enumerator);
183 }
184
185 lib->credmgr->remove_local_set(lib->credmgr, &wrapper->set);
186 wrapper->destroy(wrapper);
187
188 if (!found)
189 {
190 DBG1(DBG_CFG, "ocsp response verification failed, "
191 "no signer certificate '%Y' found", responder);
192 }
193 return verified;
194 }
195
196 /**
197 * Get the better of two OCSP responses, and check for usable OCSP info
198 */
199 static certificate_t *get_better_ocsp(certificate_t *cand, certificate_t *best,
200 x509_t *subject, x509_t *issuer,
201 cert_validation_t *valid, bool cache)
202 {
203 ocsp_response_t *response;
204 time_t revocation, this_update, next_update, valid_until;
205 crl_reason_t reason;
206 bool revoked = FALSE;
207
208 response = (ocsp_response_t*)cand;
209
210 /* check ocsp signature */
211 if (!verify_ocsp(response, &issuer->interface))
212 {
213 cand->destroy(cand);
214 return best;
215 }
216 /* check if response contains our certificate */
217 switch (response->get_status(response, subject, issuer, &revocation, &reason,
218 &this_update, &next_update))
219 {
220 case VALIDATION_REVOKED:
221 /* subject has been revoked by a valid OCSP response */
222 DBG1(DBG_CFG, "certificate was revoked on %T, reason: %N",
223 &revocation, TRUE, crl_reason_names, reason);
224 revoked = TRUE;
225 break;
226 case VALIDATION_GOOD:
227 /* results in either good or stale */
228 break;
229 default:
230 case VALIDATION_FAILED:
231 /* candidate unusable, does not contain our cert */
232 DBG1(DBG_CFG, " ocsp response contains no status on our certificate");
233 cand->destroy(cand);
234 return best;
235 }
236
237 /* select the better of the two responses */
238 if (best == NULL || certificate_is_newer(cand, best))
239 {
240 DESTROY_IF(best);
241 best = cand;
242 if (best->get_validity(best, NULL, NULL, &valid_until))
243 {
244 DBG1(DBG_CFG, " ocsp response is valid: until %T",
245 &valid_until, FALSE);
246 *valid = VALIDATION_GOOD;
247 if (cache)
248 { /* cache non-stale only, stale certs get refetched */
249 lib->credmgr->cache_cert(lib->credmgr, best);
250 }
251 }
252 else
253 {
254 DBG1(DBG_CFG, " ocsp response is stale: since %T",
255 &valid_until, FALSE);
256 *valid = VALIDATION_STALE;
257 }
258 }
259 else
260 {
261 *valid = VALIDATION_STALE;
262 cand->destroy(cand);
263 }
264 if (revoked)
265 { /* revoked always counts, even if stale */
266 *valid = VALIDATION_REVOKED;
267 }
268 return best;
269 }
270
271 /**
272 * validate a x509 certificate using OCSP
273 */
274 static cert_validation_t check_ocsp(x509_t *subject, x509_t *issuer,
275 auth_cfg_t *auth)
276 {
277 enumerator_t *enumerator;
278 cert_validation_t valid = VALIDATION_SKIPPED;
279 certificate_t *best = NULL, *current;
280 identification_t *keyid = NULL;
281 public_key_t *public;
282 chunk_t chunk;
283 char *uri = NULL;
284
285 /** lookup cache for valid OCSP responses */
286 enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
287 CERT_X509_OCSP_RESPONSE, KEY_ANY, NULL, FALSE);
288 while (enumerator->enumerate(enumerator, &current))
289 {
290 current->get_ref(current);
291 best = get_better_ocsp(current, best, subject, issuer, &valid, FALSE);
292 if (best && valid != VALIDATION_STALE)
293 {
294 DBG1(DBG_CFG, " using cached ocsp response");
295 break;
296 }
297 }
298 enumerator->destroy(enumerator);
299
300 /* derive the authorityKeyIdentifier from the issuer's public key */
301 current = &issuer->interface;
302 public = current->get_public_key(current);
303 if (public && public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &chunk))
304 {
305 keyid = identification_create_from_encoding(ID_KEY_ID, chunk);
306 }
307 /** fetch from configured OCSP responder URLs */
308 if (keyid && valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
309 {
310 enumerator = lib->credmgr->create_cdp_enumerator(lib->credmgr,
311 CERT_X509_OCSP_RESPONSE, keyid);
312 while (enumerator->enumerate(enumerator, &uri))
313 {
314 current = fetch_ocsp(uri, &subject->interface, &issuer->interface);
315 if (current)
316 {
317 best = get_better_ocsp(current, best, subject, issuer,
318 &valid, TRUE);
319 if (best && valid != VALIDATION_STALE)
320 {
321 break;
322 }
323 }
324 }
325 enumerator->destroy(enumerator);
326 }
327 DESTROY_IF(public);
328 DESTROY_IF(keyid);
329
330 /* fallback to URL fetching from subject certificate's URIs */
331 if (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
332 {
333 enumerator = subject->create_ocsp_uri_enumerator(subject);
334 while (enumerator->enumerate(enumerator, &uri))
335 {
336 current = fetch_ocsp(uri, &subject->interface, &issuer->interface);
337 if (current)
338 {
339 best = get_better_ocsp(current, best, subject, issuer,
340 &valid, TRUE);
341 if (best && valid != VALIDATION_STALE)
342 {
343 break;
344 }
345 }
346 }
347 enumerator->destroy(enumerator);
348 }
349 /* an uri was found, but no result. switch validation state to failed */
350 if (valid == VALIDATION_SKIPPED && uri)
351 {
352 valid = VALIDATION_FAILED;
353 }
354 if (auth)
355 {
356 auth->add(auth, AUTH_RULE_OCSP_VALIDATION, valid);
357 if (valid == VALIDATION_GOOD)
358 { /* successful OCSP check fulfills also CRL constraint */
359 auth->add(auth, AUTH_RULE_CRL_VALIDATION, VALIDATION_GOOD);
360 }
361 }
362 DESTROY_IF(best);
363 return valid;
364 }
365
366 /**
367 * fetch a CRL from an URL
368 */
369 static certificate_t* fetch_crl(char *url)
370 {
371 certificate_t *crl;
372 chunk_t chunk;
373
374 DBG1(DBG_CFG, " fetching crl from '%s' ...", url);
375 if (lib->fetcher->fetch(lib->fetcher, url, &chunk, FETCH_END) != SUCCESS)
376 {
377 DBG1(DBG_CFG, "crl fetching failed");
378 return NULL;
379 }
380 crl = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL,
381 BUILD_BLOB_PEM, chunk, BUILD_END);
382 chunk_free(&chunk);
383 if (!crl)
384 {
385 DBG1(DBG_CFG, "crl fetched successfully but parsing failed");
386 return NULL;
387 }
388 return crl;
389 }
390
391 /**
392 * check the signature of an CRL
393 */
394 static bool verify_crl(certificate_t *crl)
395 {
396 certificate_t *issuer;
397 enumerator_t *enumerator;
398 bool verified = FALSE;
399
400 enumerator = lib->credmgr->create_trusted_enumerator(lib->credmgr,
401 KEY_ANY, crl->get_issuer(crl), FALSE);
402 while (enumerator->enumerate(enumerator, &issuer, NULL))
403 {
404 if (lib->credmgr->issued_by(lib->credmgr, crl, issuer, NULL))
405 {
406 DBG1(DBG_CFG, " crl correctly signed by \"%Y\"",
407 issuer->get_subject(issuer));
408 verified = TRUE;
409 break;
410 }
411 }
412 enumerator->destroy(enumerator);
413
414 return verified;
415 }
416
417 /**
418 * Report the given CRL's validity and cache it if valid and requested
419 */
420 static bool is_crl_valid(certificate_t *crl, bool cache)
421 {
422 time_t valid_until;
423
424 if (crl->get_validity(crl, NULL, NULL, &valid_until))
425 {
426 DBG1(DBG_CFG, " crl is valid: until %T", &valid_until, FALSE);
427 if (cache)
428 {
429 lib->credmgr->cache_cert(lib->credmgr, crl);
430 }
431 return TRUE;
432 }
433 DBG1(DBG_CFG, " crl is stale: since %T", &valid_until, FALSE);
434 return FALSE;
435 }
436
437 /**
438 * Get the better of two CRLs, and check for usable CRL info
439 */
440 static certificate_t *get_better_crl(certificate_t *cand, certificate_t *best,
441 x509_t *subject, cert_validation_t *valid,
442 bool cache, crl_t *base)
443 {
444 enumerator_t *enumerator;
445 time_t revocation;
446 crl_reason_t reason;
447 chunk_t subject_serial, serial;
448 crl_t *crl = (crl_t*)cand;
449
450 if (base)
451 {
452 if (!crl->is_delta_crl(crl, &serial) ||
453 !chunk_equals(serial, base->get_serial(base)))
454 {
455 cand->destroy(cand);
456 return best;
457 }
458 }
459 else
460 {
461 if (crl->is_delta_crl(crl, NULL))
462 {
463 cand->destroy(cand);
464 return best;
465 }
466 }
467
468 /* check CRL signature */
469 if (!verify_crl(cand))
470 {
471 DBG1(DBG_CFG, "crl response verification failed");
472 cand->destroy(cand);
473 return best;
474 }
475
476 subject_serial = chunk_skip_zero(subject->get_serial(subject));
477 enumerator = crl->create_enumerator(crl);
478 while (enumerator->enumerate(enumerator, &serial, &revocation, &reason))
479 {
480 if (chunk_equals(subject_serial, chunk_skip_zero(serial)))
481 {
482 if (reason != CRL_REASON_CERTIFICATE_HOLD)
483 {
484 *valid = VALIDATION_REVOKED;
485 }
486 else
487 {
488 /* if the cert is on hold, a newer CRL might not contain it */
489 *valid = VALIDATION_ON_HOLD;
490 }
491 is_crl_valid(cand, cache);
492 DBG1(DBG_CFG, "certificate was revoked on %T, reason: %N",
493 &revocation, TRUE, crl_reason_names, reason);
494 enumerator->destroy(enumerator);
495 DESTROY_IF(best);
496 return cand;
497 }
498 }
499 enumerator->destroy(enumerator);
500
501 /* select the better of the two CRLs */
502 if (best == NULL || crl_is_newer(crl, (crl_t*)best))
503 {
504 DESTROY_IF(best);
505 best = cand;
506 if (is_crl_valid(best, cache))
507 {
508 *valid = VALIDATION_GOOD;
509 }
510 else
511 {
512 *valid = VALIDATION_STALE;
513 }
514 }
515 else
516 {
517 *valid = VALIDATION_STALE;
518 cand->destroy(cand);
519 }
520 return best;
521 }
522
523 /**
524 * Find or fetch a certificate for a given crlIssuer
525 */
526 static cert_validation_t find_crl(x509_t *subject, identification_t *issuer,
527 crl_t *base, certificate_t **best,
528 bool *uri_found)
529 {
530 cert_validation_t valid = VALIDATION_SKIPPED;
531 enumerator_t *enumerator;
532 certificate_t *current;
533 char *uri;
534
535 /* find a cached (delta) crl */
536 enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
537 CERT_X509_CRL, KEY_ANY, issuer, FALSE);
538 while (enumerator->enumerate(enumerator, &current))
539 {
540 current->get_ref(current);
541 *best = get_better_crl(current, *best, subject, &valid, FALSE, base);
542 if (*best && valid != VALIDATION_STALE)
543 {
544 DBG1(DBG_CFG, " using cached crl");
545 break;
546 }
547 }
548 enumerator->destroy(enumerator);
549
550 /* fallback to fetching crls from credential sets cdps */
551 if (!base && valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
552 {
553 enumerator = lib->credmgr->create_cdp_enumerator(lib->credmgr,
554 CERT_X509_CRL, issuer);
555 while (enumerator->enumerate(enumerator, &uri))
556 {
557 *uri_found = TRUE;
558 current = fetch_crl(uri);
559 if (current)
560 {
561 if (!current->has_issuer(current, issuer))
562 {
563 DBG1(DBG_CFG, "issuer of fetched CRL '%Y' does not match CRL "
564 "issuer '%Y'", current->get_issuer(current), issuer);
565 current->destroy(current);
566 continue;
567 }
568 *best = get_better_crl(current, *best, subject,
569 &valid, TRUE, base);
570 if (*best && valid != VALIDATION_STALE)
571 {
572 break;
573 }
574 }
575 }
576 enumerator->destroy(enumerator);
577 }
578 return valid;
579 }
580
581 /**
582 * Check if the issuer of the given CRL matches
583 */
584 static bool check_issuer(certificate_t *crl, x509_t *issuer, x509_cdp_t *cdp)
585 {
586 certificate_t *cissuer = (certificate_t*)issuer;
587 identification_t *id;
588 chunk_t chunk;
589 bool matches = FALSE;
590
591 if (cdp->issuer)
592 {
593 return crl->has_issuer(crl, cdp->issuer);
594 }
595 /* check SKI/AKI first, but fall back to DN matching */
596 chunk = issuer->get_subjectKeyIdentifier(issuer);
597 if (chunk.len)
598 {
599 id = identification_create_from_encoding(ID_KEY_ID, chunk);
600 matches = crl->has_issuer(crl, id);
601 id->destroy(id);
602 }
603 return matches || crl->has_issuer(crl, cissuer->get_subject(cissuer));
604 }
605
606 /**
607 * Look for a delta CRL for a given base CRL
608 */
609 static cert_validation_t check_delta_crl(x509_t *subject, x509_t *issuer,
610 crl_t *base, cert_validation_t base_valid)
611 {
612 cert_validation_t valid = VALIDATION_SKIPPED;
613 certificate_t *best = NULL, *current, *cissuer = (certificate_t*)issuer;
614 enumerator_t *enumerator;
615 identification_t *id;
616 x509_cdp_t *cdp;
617 chunk_t chunk;
618 bool uri;
619
620 /* find cached delta CRL via subjectKeyIdentifier */
621 chunk = issuer->get_subjectKeyIdentifier(issuer);
622 if (chunk.len)
623 {
624 id = identification_create_from_encoding(ID_KEY_ID, chunk);
625 valid = find_crl(subject, id, base, &best, &uri);
626 id->destroy(id);
627 }
628
629 /* find delta CRL by CRLIssuer */
630 enumerator = subject->create_crl_uri_enumerator(subject);
631 while (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED &&
632 enumerator->enumerate(enumerator, &cdp))
633 {
634 if (cdp->issuer)
635 {
636 valid = find_crl(subject, cdp->issuer, base, &best, &uri);
637 }
638 }
639 enumerator->destroy(enumerator);
640
641 /* fetch from URIs found in Freshest CRL extension */
642 enumerator = base->create_delta_crl_uri_enumerator(base);
643 while (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED &&
644 enumerator->enumerate(enumerator, &cdp))
645 {
646 current = fetch_crl(cdp->uri);
647 if (current)
648 {
649 if (!check_issuer(current, issuer, cdp))
650 {
651 DBG1(DBG_CFG, "issuer of fetched delta CRL '%Y' does not match "
652 "certificate's %sissuer '%Y'",
653 current->get_issuer(current), cdp->issuer ? "CRL " : "",
654 cdp->issuer ?: cissuer->get_subject(cissuer));
655 current->destroy(current);
656 continue;
657 }
658 best = get_better_crl(current, best, subject, &valid, TRUE, base);
659 if (best && valid != VALIDATION_STALE)
660 {
661 break;
662 }
663 }
664 }
665 enumerator->destroy(enumerator);
666
667 if (best)
668 {
669 best->destroy(best);
670 return valid;
671 }
672 return base_valid;
673 }
674
675 /**
676 * validate a x509 certificate using CRL
677 */
678 static cert_validation_t check_crl(x509_t *subject, x509_t *issuer,
679 auth_cfg_t *auth)
680 {
681 cert_validation_t valid = VALIDATION_SKIPPED;
682 certificate_t *best = NULL, *cissuer = (certificate_t*)issuer;
683 identification_t *id;
684 x509_cdp_t *cdp;
685 bool uri_found = FALSE;
686 certificate_t *current;
687 enumerator_t *enumerator;
688 chunk_t chunk;
689
690 /* use issuers subjectKeyIdentifier to find a cached CRL / fetch from CDP */
691 chunk = issuer->get_subjectKeyIdentifier(issuer);
692 if (chunk.len)
693 {
694 id = identification_create_from_encoding(ID_KEY_ID, chunk);
695 valid = find_crl(subject, id, NULL, &best, &uri_found);
696 id->destroy(id);
697 }
698
699 /* find a cached CRL or fetch via configured CDP via CRLIssuer */
700 enumerator = subject->create_crl_uri_enumerator(subject);
701 while (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED &&
702 enumerator->enumerate(enumerator, &cdp))
703 {
704 if (cdp->issuer)
705 {
706 valid = find_crl(subject, cdp->issuer, NULL, &best, &uri_found);
707 }
708 }
709 enumerator->destroy(enumerator);
710
711 /* fallback to fetching CRLs from CDPs found in subjects certificate */
712 if (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
713 {
714 enumerator = subject->create_crl_uri_enumerator(subject);
715 while (enumerator->enumerate(enumerator, &cdp))
716 {
717 uri_found = TRUE;
718 current = fetch_crl(cdp->uri);
719 if (current)
720 {
721 if (!check_issuer(current, issuer, cdp))
722 {
723 DBG1(DBG_CFG, "issuer of fetched CRL '%Y' does not match "
724 "certificate's %sissuer '%Y'",
725 current->get_issuer(current), cdp->issuer ? "CRL " : "",
726 cdp->issuer ?: cissuer->get_subject(cissuer));
727 current->destroy(current);
728 continue;
729 }
730 best = get_better_crl(current, best, subject, &valid,
731 TRUE, NULL);
732 if (best && valid != VALIDATION_STALE)
733 {
734 break;
735 }
736 }
737 }
738 enumerator->destroy(enumerator);
739 }
740
741 /* look for delta CRLs */
742 if (best && (valid == VALIDATION_GOOD || valid == VALIDATION_STALE))
743 {
744 valid = check_delta_crl(subject, issuer, (crl_t*)best, valid);
745 }
746
747 /* an uri was found, but no result. switch validation state to failed */
748 if (valid == VALIDATION_SKIPPED && uri_found)
749 {
750 valid = VALIDATION_FAILED;
751 }
752 if (auth)
753 {
754 if (valid == VALIDATION_SKIPPED)
755 { /* if we skipped CRL validation, we use the result of OCSP for
756 * constraint checking */
757 auth->add(auth, AUTH_RULE_CRL_VALIDATION,
758 auth->get(auth, AUTH_RULE_OCSP_VALIDATION));
759 }
760 else
761 {
762 auth->add(auth, AUTH_RULE_CRL_VALIDATION, valid);
763 }
764 }
765 DESTROY_IF(best);
766 return valid;
767 }
768
769 METHOD(cert_validator_t, validate, bool,
770 private_revocation_validator_t *this, certificate_t *subject,
771 certificate_t *issuer, bool online, u_int pathlen, bool anchor,
772 auth_cfg_t *auth)
773 {
774 if (online && (this->enable_ocsp || this->enable_crl) &&
775 subject->get_type(subject) == CERT_X509 &&
776 issuer->get_type(issuer) == CERT_X509)
777 {
778 DBG1(DBG_CFG, "checking certificate status of \"%Y\"",
779 subject->get_subject(subject));
780
781 if (this->enable_ocsp)
782 {
783 switch (check_ocsp((x509_t*)subject, (x509_t*)issuer,
784 pathlen ? NULL : auth))
785 {
786 case VALIDATION_GOOD:
787 DBG1(DBG_CFG, "certificate status is good");
788 return TRUE;
789 case VALIDATION_REVOKED:
790 case VALIDATION_ON_HOLD:
791 /* has already been logged */
792 lib->credmgr->call_hook(lib->credmgr, CRED_HOOK_REVOKED,
793 subject);
794 return FALSE;
795 case VALIDATION_SKIPPED:
796 DBG2(DBG_CFG, "ocsp check skipped, no ocsp found");
797 break;
798 case VALIDATION_STALE:
799 DBG1(DBG_CFG, "ocsp information stale, fallback to crl");
800 break;
801 case VALIDATION_FAILED:
802 DBG1(DBG_CFG, "ocsp check failed, fallback to crl");
803 break;
804 }
805 }
806
807 if (this->enable_crl)
808 {
809 switch (check_crl((x509_t*)subject, (x509_t*)issuer,
810 pathlen ? NULL : auth))
811 {
812 case VALIDATION_GOOD:
813 DBG1(DBG_CFG, "certificate status is good");
814 return TRUE;
815 case VALIDATION_REVOKED:
816 case VALIDATION_ON_HOLD:
817 /* has already been logged */
818 lib->credmgr->call_hook(lib->credmgr, CRED_HOOK_REVOKED,
819 subject);
820 return FALSE;
821 case VALIDATION_FAILED:
822 case VALIDATION_SKIPPED:
823 DBG1(DBG_CFG, "certificate status is not available");
824 break;
825 case VALIDATION_STALE:
826 DBG1(DBG_CFG, "certificate status is unknown, crl is stale");
827 break;
828 }
829 }
830
831 lib->credmgr->call_hook(lib->credmgr, CRED_HOOK_VALIDATION_FAILED,
832 subject);
833 }
834 return TRUE;
835 }
836
837 METHOD(revocation_validator_t, destroy, void,
838 private_revocation_validator_t *this)
839 {
840 free(this);
841 }
842
843 /**
844 * See header
845 */
846 revocation_validator_t *revocation_validator_create()
847 {
848 private_revocation_validator_t *this;
849
850 INIT(this,
851 .public = {
852 .validator.validate = _validate,
853 .destroy = _destroy,
854 },
855 .enable_ocsp = lib->settings->get_bool(lib->settings,
856 "%s.plugins.revocation.enable_ocsp", TRUE, lib->ns),
857 .enable_crl = lib->settings->get_bool(lib->settings,
858 "%s.plugins.revocation.enable_crl", TRUE, lib->ns),
859 );
860
861 if (!this->enable_ocsp)
862 {
863 DBG1(DBG_LIB, "all OCSP validation disabled");
864 }
865 if (!this->enable_crl)
866 {
867 DBG1(DBG_LIB, "all CRL validation disabled");
868 }
869 return &this->public;
870 }