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