Merge branch 'ikev1-clean' into ikev1-master
[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 <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 /**
42 * Do an OCSP request
43 */
44 static certificate_t *fetch_ocsp(char *url, certificate_t *subject,
45 certificate_t *issuer)
46 {
47 certificate_t *request, *response;
48 chunk_t send, receive;
49
50 /* TODO: requestor name, signature */
51 request = lib->creds->create(lib->creds,
52 CRED_CERTIFICATE, CERT_X509_OCSP_REQUEST,
53 BUILD_CA_CERT, issuer,
54 BUILD_CERT, subject, BUILD_END);
55 if (!request)
56 {
57 DBG1(DBG_CFG, "generating ocsp request failed");
58 return NULL;
59 }
60
61 if (!request->get_encoding(request, CERT_ASN1_DER, &send))
62 {
63 DBG1(DBG_CFG, "encoding ocsp request failed");
64 request->destroy(request);
65 return NULL;
66 }
67 request->destroy(request);
68
69 DBG1(DBG_CFG, " requesting ocsp status from '%s' ...", url);
70 if (lib->fetcher->fetch(lib->fetcher, url, &receive,
71 FETCH_REQUEST_DATA, send,
72 FETCH_REQUEST_TYPE, "application/ocsp-request",
73 FETCH_END) != SUCCESS)
74 {
75 DBG1(DBG_CFG, "ocsp request to %s failed", url);
76 chunk_free(&send);
77 return NULL;
78 }
79 chunk_free(&send);
80
81 response = lib->creds->create(lib->creds,
82 CRED_CERTIFICATE, CERT_X509_OCSP_RESPONSE,
83 BUILD_BLOB_ASN1_DER, receive, BUILD_END);
84 chunk_free(&receive);
85 if (!response)
86 {
87 DBG1(DBG_CFG, "parsing ocsp response failed");
88 return NULL;
89 }
90 return response;
91 }
92
93 /**
94 * check the signature of an OCSP response
95 */
96 static bool verify_ocsp(ocsp_response_t *response, auth_cfg_t *auth)
97 {
98 certificate_t *issuer, *subject;
99 identification_t *responder;
100 ocsp_response_wrapper_t *wrapper;
101 enumerator_t *enumerator;
102 auth_cfg_t *current;
103 bool verified = FALSE;
104
105 wrapper = ocsp_response_wrapper_create((ocsp_response_t*)response);
106 lib->credmgr->add_local_set(lib->credmgr, &wrapper->set, FALSE);
107
108 subject = &response->certificate;
109 responder = subject->get_issuer(subject);
110 enumerator = lib->credmgr->create_trusted_enumerator(lib->credmgr,
111 KEY_ANY, responder, FALSE);
112 while (enumerator->enumerate(enumerator, &issuer, &current))
113 {
114 if (lib->credmgr->issued_by(lib->credmgr, subject, issuer))
115 {
116 DBG1(DBG_CFG, " ocsp response correctly signed by \"%Y\"",
117 issuer->get_subject(issuer));
118 if (auth)
119 {
120 auth->merge(auth, current, FALSE);
121 }
122 verified = TRUE;
123 break;
124 }
125 }
126 enumerator->destroy(enumerator);
127
128 lib->credmgr->remove_local_set(lib->credmgr, &wrapper->set);
129 wrapper->destroy(wrapper);
130 return verified;
131 }
132
133 /**
134 * Get the better of two OCSP responses, and check for usable OCSP info
135 */
136 static certificate_t *get_better_ocsp(certificate_t *cand, certificate_t *best,
137 x509_t *subject, x509_t *issuer, cert_validation_t *valid,
138 auth_cfg_t *auth, bool cache)
139 {
140 ocsp_response_t *response;
141 time_t revocation, this_update, next_update, valid_until;
142 crl_reason_t reason;
143 bool revoked = FALSE;
144
145 response = (ocsp_response_t*)cand;
146
147 /* check ocsp signature */
148 if (!verify_ocsp(response, auth))
149 {
150 DBG1(DBG_CFG, "ocsp response verification failed");
151 cand->destroy(cand);
152 return best;
153 }
154 /* check if response contains our certificate */
155 switch (response->get_status(response, subject, issuer, &revocation, &reason,
156 &this_update, &next_update))
157 {
158 case VALIDATION_REVOKED:
159 /* subject has been revoked by a valid OCSP response */
160 DBG1(DBG_CFG, "certificate was revoked on %T, reason: %N",
161 &revocation, TRUE, crl_reason_names, reason);
162 revoked = TRUE;
163 break;
164 case VALIDATION_GOOD:
165 /* results in either good or stale */
166 break;
167 default:
168 case VALIDATION_FAILED:
169 /* candidate unusable, does not contain our cert */
170 DBG1(DBG_CFG, " ocsp response contains no status on our certificate");
171 cand->destroy(cand);
172 return best;
173 }
174
175 /* select the better of the two responses */
176 if (best == NULL || certificate_is_newer(cand, best))
177 {
178 DESTROY_IF(best);
179 best = cand;
180 if (best->get_validity(best, NULL, NULL, &valid_until))
181 {
182 DBG1(DBG_CFG, " ocsp response is valid: until %T",
183 &valid_until, FALSE);
184 *valid = VALIDATION_GOOD;
185 if (cache)
186 { /* cache non-stale only, stale certs get refetched */
187 lib->credmgr->cache_cert(lib->credmgr, best);
188 }
189 }
190 else
191 {
192 DBG1(DBG_CFG, " ocsp response is stale: since %T",
193 &valid_until, FALSE);
194 *valid = VALIDATION_STALE;
195 }
196 }
197 else
198 {
199 *valid = VALIDATION_STALE;
200 cand->destroy(cand);
201 }
202 if (revoked)
203 { /* revoked always counts, even if stale */
204 *valid = VALIDATION_REVOKED;
205 }
206 return best;
207 }
208
209 /**
210 * validate a x509 certificate using OCSP
211 */
212 static cert_validation_t check_ocsp(x509_t *subject, x509_t *issuer,
213 auth_cfg_t *auth)
214 {
215 enumerator_t *enumerator;
216 cert_validation_t valid = VALIDATION_SKIPPED;
217 certificate_t *best = NULL, *current;
218 identification_t *keyid = NULL;
219 public_key_t *public;
220 chunk_t chunk;
221 char *uri = NULL;
222
223 /** lookup cache for valid OCSP responses */
224 enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
225 CERT_X509_OCSP_RESPONSE, KEY_ANY, NULL, FALSE);
226 while (enumerator->enumerate(enumerator, &current))
227 {
228 current->get_ref(current);
229 best = get_better_ocsp(current, best, subject, issuer,
230 &valid, auth, FALSE);
231 if (best && valid != VALIDATION_STALE)
232 {
233 DBG1(DBG_CFG, " using cached ocsp response");
234 break;
235 }
236 }
237 enumerator->destroy(enumerator);
238
239 /* derive the authorityKeyIdentifier from the issuer's public key */
240 current = &issuer->interface;
241 public = current->get_public_key(current);
242 if (public && public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &chunk))
243 {
244 keyid = identification_create_from_encoding(ID_KEY_ID, chunk);
245 }
246 /** fetch from configured OCSP responder URLs */
247 if (keyid && valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
248 {
249 enumerator = lib->credmgr->create_cdp_enumerator(lib->credmgr,
250 CERT_X509_OCSP_RESPONSE, keyid);
251 while (enumerator->enumerate(enumerator, &uri))
252 {
253 current = fetch_ocsp(uri, &subject->interface, &issuer->interface);
254 if (current)
255 {
256 best = get_better_ocsp(current, best, subject, issuer,
257 &valid, auth, TRUE);
258 if (best && valid != VALIDATION_STALE)
259 {
260 break;
261 }
262 }
263 }
264 enumerator->destroy(enumerator);
265 }
266 DESTROY_IF(public);
267 DESTROY_IF(keyid);
268
269 /* fallback to URL fetching from subject certificate's URIs */
270 if (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
271 {
272 enumerator = subject->create_ocsp_uri_enumerator(subject);
273 while (enumerator->enumerate(enumerator, &uri))
274 {
275 current = fetch_ocsp(uri, &subject->interface, &issuer->interface);
276 if (current)
277 {
278 best = get_better_ocsp(current, best, subject, issuer,
279 &valid, auth, TRUE);
280 if (best && valid != VALIDATION_STALE)
281 {
282 break;
283 }
284 }
285 }
286 enumerator->destroy(enumerator);
287 }
288 /* an uri was found, but no result. switch validation state to failed */
289 if (valid == VALIDATION_SKIPPED && uri)
290 {
291 valid = VALIDATION_FAILED;
292 }
293 if (auth)
294 {
295 auth->add(auth, AUTH_RULE_OCSP_VALIDATION, valid);
296 if (valid == VALIDATION_GOOD)
297 { /* successful OCSP check fulfills also CRL constraint */
298 auth->add(auth, AUTH_RULE_CRL_VALIDATION, VALIDATION_GOOD);
299 }
300 }
301 DESTROY_IF(best);
302 return valid;
303 }
304
305 /**
306 * fetch a CRL from an URL
307 */
308 static certificate_t* fetch_crl(char *url)
309 {
310 certificate_t *crl;
311 chunk_t chunk;
312
313 DBG1(DBG_CFG, " fetching crl from '%s' ...", url);
314 if (lib->fetcher->fetch(lib->fetcher, url, &chunk, FETCH_END) != SUCCESS)
315 {
316 DBG1(DBG_CFG, "crl fetching failed");
317 return NULL;
318 }
319 crl = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL,
320 BUILD_BLOB_ASN1_DER, chunk, BUILD_END);
321 chunk_free(&chunk);
322 if (!crl)
323 {
324 DBG1(DBG_CFG, "crl fetched successfully but parsing failed");
325 return NULL;
326 }
327 return crl;
328 }
329
330 /**
331 * check the signature of an CRL
332 */
333 static bool verify_crl(certificate_t *crl, auth_cfg_t *auth)
334 {
335 certificate_t *issuer;
336 enumerator_t *enumerator;
337 bool verified = FALSE;
338 auth_cfg_t *current;
339
340 enumerator = lib->credmgr->create_trusted_enumerator(lib->credmgr,
341 KEY_ANY, crl->get_issuer(crl), FALSE);
342 while (enumerator->enumerate(enumerator, &issuer, &current))
343 {
344 if (lib->credmgr->issued_by(lib->credmgr, crl, issuer))
345 {
346 DBG1(DBG_CFG, " crl correctly signed by \"%Y\"",
347 issuer->get_subject(issuer));
348 if (auth)
349 {
350 auth->merge(auth, current, FALSE);
351 }
352 verified = TRUE;
353 break;
354 }
355 }
356 enumerator->destroy(enumerator);
357
358 return verified;
359 }
360
361 /**
362 * Get the better of two CRLs, and check for usable CRL info
363 */
364 static certificate_t *get_better_crl(certificate_t *cand, certificate_t *best,
365 x509_t *subject, cert_validation_t *valid, auth_cfg_t *auth,
366 bool cache, crl_t *base)
367 {
368 enumerator_t *enumerator;
369 time_t revocation, valid_until;
370 crl_reason_t reason;
371 chunk_t serial;
372 crl_t *crl = (crl_t*)cand;
373
374 if (base)
375 {
376 if (!crl->is_delta_crl(crl, &serial) ||
377 !chunk_equals(serial, base->get_serial(base)))
378 {
379 cand->destroy(cand);
380 return best;
381 }
382 }
383 else
384 {
385 if (crl->is_delta_crl(crl, NULL))
386 {
387 cand->destroy(cand);
388 return best;
389 }
390 }
391
392 /* check CRL signature */
393 if (!verify_crl(cand, auth))
394 {
395 DBG1(DBG_CFG, "crl response verification failed");
396 cand->destroy(cand);
397 return best;
398 }
399
400 enumerator = crl->create_enumerator(crl);
401 while (enumerator->enumerate(enumerator, &serial, &revocation, &reason))
402 {
403 if (chunk_equals(serial, subject->get_serial(subject)))
404 {
405 DBG1(DBG_CFG, "certificate was revoked on %T, reason: %N",
406 &revocation, TRUE, crl_reason_names, reason);
407 if (reason != CRL_REASON_CERTIFICATE_HOLD)
408 {
409 *valid = VALIDATION_REVOKED;
410 }
411 else
412 {
413 /* if the cert is on hold, a newer CRL might not contain it */
414 *valid = VALIDATION_ON_HOLD;
415 }
416 enumerator->destroy(enumerator);
417 DESTROY_IF(best);
418 return cand;
419 }
420 }
421 enumerator->destroy(enumerator);
422
423 /* select the better of the two CRLs */
424 if (best == NULL || crl_is_newer(crl, (crl_t*)best))
425 {
426 DESTROY_IF(best);
427 best = cand;
428 if (best->get_validity(best, NULL, NULL, &valid_until))
429 {
430 DBG1(DBG_CFG, " crl is valid: until %T", &valid_until, FALSE);
431 *valid = VALIDATION_GOOD;
432 if (cache)
433 { /* we cache non-stale crls only, as a stale crls are refetched */
434 lib->credmgr->cache_cert(lib->credmgr, best);
435 }
436 }
437 else
438 {
439 DBG1(DBG_CFG, " crl is stale: since %T", &valid_until, FALSE);
440 *valid = VALIDATION_STALE;
441 }
442 }
443 else
444 {
445 *valid = VALIDATION_STALE;
446 cand->destroy(cand);
447 }
448 return best;
449 }
450
451 /**
452 * Find or fetch a certificate for a given crlIssuer
453 */
454 static cert_validation_t find_crl(x509_t *subject, identification_t *issuer,
455 auth_cfg_t *auth, crl_t *base,
456 certificate_t **best, bool *uri_found)
457 {
458 cert_validation_t valid = VALIDATION_SKIPPED;
459 enumerator_t *enumerator;
460 certificate_t *current;
461 char *uri;
462
463 /* find a cached (delta) crl */
464 enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
465 CERT_X509_CRL, KEY_ANY, issuer, FALSE);
466 while (enumerator->enumerate(enumerator, &current))
467 {
468 current->get_ref(current);
469 *best = get_better_crl(current, *best, subject, &valid,
470 auth, FALSE, base);
471 if (*best && valid != VALIDATION_STALE)
472 {
473 DBG1(DBG_CFG, " using cached crl");
474 break;
475 }
476 }
477 enumerator->destroy(enumerator);
478
479 /* fallback to fetching crls from credential sets cdps */
480 if (!base && valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
481 {
482 enumerator = lib->credmgr->create_cdp_enumerator(lib->credmgr,
483 CERT_X509_CRL, issuer);
484 while (enumerator->enumerate(enumerator, &uri))
485 {
486 *uri_found = TRUE;
487 current = fetch_crl(uri);
488 if (current)
489 {
490 if (!current->has_issuer(current, issuer))
491 {
492 DBG1(DBG_CFG, "issuer of fetched CRL '%Y' does not match CRL "
493 "issuer '%Y'", current->get_issuer(current), issuer);
494 current->destroy(current);
495 continue;
496 }
497 *best = get_better_crl(current, *best, subject,
498 &valid, auth, TRUE, base);
499 if (*best && valid != VALIDATION_STALE)
500 {
501 break;
502 }
503 }
504 }
505 enumerator->destroy(enumerator);
506 }
507 return valid;
508 }
509
510 /**
511 * Look for a delta CRL for a given base CRL
512 */
513 static cert_validation_t check_delta_crl(x509_t *subject, x509_t *issuer,
514 crl_t *base, cert_validation_t base_valid, auth_cfg_t *auth)
515 {
516 cert_validation_t valid = VALIDATION_SKIPPED;
517 certificate_t *best = NULL, *current;
518 enumerator_t *enumerator;
519 identification_t *id;
520 x509_cdp_t *cdp;
521 chunk_t chunk;
522 bool uri;
523
524 /* find cached delta CRL via subjectKeyIdentifier */
525 chunk = issuer->get_subjectKeyIdentifier(issuer);
526 if (chunk.len)
527 {
528 id = identification_create_from_encoding(ID_KEY_ID, chunk);
529 valid = find_crl(subject, id, auth, base, &best, &uri);
530 id->destroy(id);
531 }
532
533 /* find delta CRL by CRLIssuer */
534 enumerator = subject->create_crl_uri_enumerator(subject);
535 while (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED &&
536 enumerator->enumerate(enumerator, &cdp))
537 {
538 if (cdp->issuer)
539 {
540 valid = find_crl(subject, cdp->issuer, auth, base, &best, &uri);
541 }
542 }
543 enumerator->destroy(enumerator);
544
545 /* fetch from URIs found in Freshest CRL extension */
546 enumerator = base->create_delta_crl_uri_enumerator(base);
547 while (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED &&
548 enumerator->enumerate(enumerator, &cdp))
549 {
550 current = fetch_crl(cdp->uri);
551 if (current)
552 {
553 if (cdp->issuer && !current->has_issuer(current, cdp->issuer))
554 {
555 DBG1(DBG_CFG, "issuer of fetched delta CRL '%Y' does not match "
556 "certificates CRL issuer '%Y'",
557 current->get_issuer(current), cdp->issuer);
558 current->destroy(current);
559 continue;
560 }
561 best = get_better_crl(current, best, subject, &valid,
562 auth, TRUE, base);
563 if (best && valid != VALIDATION_STALE)
564 {
565 break;
566 }
567 }
568 }
569 enumerator->destroy(enumerator);
570
571 if (best)
572 {
573 best->destroy(best);
574 return valid;
575 }
576 return base_valid;
577 }
578
579
580 /**
581 * validate a x509 certificate using CRL
582 */
583 static cert_validation_t check_crl(x509_t *subject, x509_t *issuer,
584 auth_cfg_t *auth)
585 {
586 cert_validation_t valid = VALIDATION_SKIPPED;
587 certificate_t *best = NULL;
588 identification_t *id;
589 x509_cdp_t *cdp;
590 bool uri_found = FALSE;
591 certificate_t *current;
592 enumerator_t *enumerator;
593 chunk_t chunk;
594
595 /* use issuers subjectKeyIdentifier to find a cached CRL / fetch from CDP */
596 chunk = issuer->get_subjectKeyIdentifier(issuer);
597 if (chunk.len)
598 {
599 id = identification_create_from_encoding(ID_KEY_ID, chunk);
600 valid = find_crl(subject, id, auth, NULL, &best, &uri_found);
601 id->destroy(id);
602 }
603
604 /* find a cached CRL or fetch via configured CDP via CRLIssuer */
605 enumerator = subject->create_crl_uri_enumerator(subject);
606 while (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED &&
607 enumerator->enumerate(enumerator, &cdp))
608 {
609 if (cdp->issuer)
610 {
611 valid = find_crl(subject, cdp->issuer, auth, NULL,
612 &best, &uri_found);
613 }
614 }
615 enumerator->destroy(enumerator);
616
617 /* fallback to fetching CRLs from CDPs found in subjects certificate */
618 if (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
619 {
620 enumerator = subject->create_crl_uri_enumerator(subject);
621 while (enumerator->enumerate(enumerator, &cdp))
622 {
623 uri_found = TRUE;
624 current = fetch_crl(cdp->uri);
625 if (current)
626 {
627 if (cdp->issuer && !current->has_issuer(current, cdp->issuer))
628 {
629 DBG1(DBG_CFG, "issuer of fetched CRL '%Y' does not match "
630 "certificates CRL issuer '%Y'",
631 current->get_issuer(current), cdp->issuer);
632 current->destroy(current);
633 continue;
634 }
635 best = get_better_crl(current, best, subject, &valid,
636 auth, TRUE, NULL);
637 if (best && valid != VALIDATION_STALE)
638 {
639 break;
640 }
641 }
642 }
643 enumerator->destroy(enumerator);
644 }
645
646 /* look for delta CRLs */
647 if (best && (valid == VALIDATION_GOOD || valid == VALIDATION_STALE))
648 {
649 valid = check_delta_crl(subject, issuer, (crl_t*)best, valid, auth);
650 }
651
652 /* an uri was found, but no result. switch validation state to failed */
653 if (valid == VALIDATION_SKIPPED && uri_found)
654 {
655 valid = VALIDATION_FAILED;
656 }
657 if (auth)
658 {
659 if (valid == VALIDATION_SKIPPED)
660 { /* if we skipped CRL validation, we use the result of OCSP for
661 * constraint checking */
662 auth->add(auth, AUTH_RULE_CRL_VALIDATION,
663 auth->get(auth, AUTH_RULE_OCSP_VALIDATION));
664 }
665 else
666 {
667 auth->add(auth, AUTH_RULE_CRL_VALIDATION, valid);
668 }
669 }
670 DESTROY_IF(best);
671 return valid;
672 }
673
674 METHOD(cert_validator_t, validate, bool,
675 private_revocation_validator_t *this, certificate_t *subject,
676 certificate_t *issuer, bool online, u_int pathlen, bool anchor,
677 auth_cfg_t *auth)
678 {
679 if (subject->get_type(subject) == CERT_X509 &&
680 issuer->get_type(issuer) == CERT_X509 &&
681 online)
682 {
683 DBG1(DBG_CFG, "checking certificate status of \"%Y\"",
684 subject->get_subject(subject));
685 switch (check_ocsp((x509_t*)subject, (x509_t*)issuer,
686 pathlen ? NULL : auth))
687 {
688 case VALIDATION_GOOD:
689 DBG1(DBG_CFG, "certificate status is good");
690 return TRUE;
691 case VALIDATION_REVOKED:
692 case VALIDATION_ON_HOLD:
693 /* has already been logged */
694 return FALSE;
695 case VALIDATION_SKIPPED:
696 DBG2(DBG_CFG, "ocsp check skipped, no ocsp found");
697 break;
698 case VALIDATION_STALE:
699 DBG1(DBG_CFG, "ocsp information stale, fallback to crl");
700 break;
701 case VALIDATION_FAILED:
702 DBG1(DBG_CFG, "ocsp check failed, fallback to crl");
703 break;
704 }
705 switch (check_crl((x509_t*)subject, (x509_t*)issuer,
706 pathlen ? NULL : auth))
707 {
708 case VALIDATION_GOOD:
709 DBG1(DBG_CFG, "certificate status is good");
710 return TRUE;
711 case VALIDATION_REVOKED:
712 case VALIDATION_ON_HOLD:
713 /* has already been logged */
714 return FALSE;
715 case VALIDATION_FAILED:
716 case VALIDATION_SKIPPED:
717 DBG1(DBG_CFG, "certificate status is not available");
718 break;
719 case VALIDATION_STALE:
720 DBG1(DBG_CFG, "certificate status is unknown, crl is stale");
721 break;
722 }
723 }
724 return TRUE;
725 }
726
727 METHOD(revocation_validator_t, destroy, void,
728 private_revocation_validator_t *this)
729 {
730 free(this);
731 }
732
733 /**
734 * See header
735 */
736 revocation_validator_t *revocation_validator_create()
737 {
738 private_revocation_validator_t *this;
739
740 INIT(this,
741 .public = {
742 .validator.validate = _validate,
743 .destroy = _destroy,
744 },
745 );
746
747 return &this->public;
748 }