2 * Copyright (C) 2010 Martin Willi
3 * Copyright (C) 2010 revosec AG
4 * Copyright (C) 2009 Andreas Steffen
5 * Hochschule fuer Technik Rapperswil
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>.
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
18 #include "revocation_validator.h"
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>
28 typedef struct private_revocation_validator_t private_revocation_validator_t
;
31 * Private data of an revocation_validator_t object.
33 struct private_revocation_validator_t
{
36 * Public revocation_validator_t interface.
38 revocation_validator_t
public;
41 * Enable OCSP validation
46 * Enable CRL validation
55 static certificate_t
*fetch_ocsp(char *url
, certificate_t
*subject
,
56 certificate_t
*issuer
)
58 certificate_t
*request
, *response
;
59 chunk_t send
, receive
;
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
);
68 DBG1(DBG_CFG
, "generating ocsp request failed");
72 if (!request
->get_encoding(request
, CERT_ASN1_DER
, &send
))
74 DBG1(DBG_CFG
, "encoding ocsp request failed");
75 request
->destroy(request
);
78 request
->destroy(request
);
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
)
86 DBG1(DBG_CFG
, "ocsp request to %s failed", url
);
92 response
= lib
->creds
->create(lib
->creds
,
93 CRED_CERTIFICATE
, CERT_X509_OCSP_RESPONSE
,
94 BUILD_BLOB_ASN1_DER
, receive
, BUILD_END
);
98 DBG1(DBG_CFG
, "parsing ocsp response failed");
105 * check the signature of an OCSP response
107 static bool verify_ocsp(ocsp_response_t
*response
, certificate_t
*ca
)
109 certificate_t
*issuer
, *subject
;
110 identification_t
*responder
;
111 ocsp_response_wrapper_t
*wrapper
;
112 enumerator_t
*enumerator
;
114 bool verified
= FALSE
, found
= FALSE
;
116 wrapper
= ocsp_response_wrapper_create((ocsp_response_t
*)response
);
117 lib
->credmgr
->add_local_set(lib
->credmgr
, &wrapper
->set
, FALSE
);
119 subject
= &response
->certificate
;
120 responder
= subject
->get_issuer(subject
);
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
))
127 x509
= (x509_t
*)issuer
;
128 if (!issuer
->get_validity(issuer
, NULL
, NULL
, NULL
))
129 { /* OCSP signer currently invalid */
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 */
138 if (!(x509
->get_flags(x509
) & X509_OCSP_SIGNER
))
139 { /* delegated OCSP signer does not have OCSP signer flag */
144 if (lib
->credmgr
->issued_by(lib
->credmgr
, subject
, issuer
, NULL
))
146 DBG1(DBG_CFG
, " ocsp response correctly signed by \"%Y\"",
147 issuer
->get_subject(issuer
));
151 DBG1(DBG_CFG
, "ocsp response verification failed, "
152 "invalid signature");
154 enumerator
->destroy(enumerator
);
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
))
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
))
171 if (lib
->credmgr
->issued_by(lib
->credmgr
, subject
, issuer
, NULL
))
173 DBG1(DBG_CFG
, " ocsp response correctly signed by \"%Y\"",
174 issuer
->get_subject(issuer
));
178 DBG1(DBG_CFG
, "ocsp response verification failed, "
179 "invalid signature");
182 enumerator
->destroy(enumerator
);
185 lib
->credmgr
->remove_local_set(lib
->credmgr
, &wrapper
->set
);
186 wrapper
->destroy(wrapper
);
190 DBG1(DBG_CFG
, "ocsp response verification failed, "
191 "no signer certificate '%Y' found", responder
);
197 * Get the better of two OCSP responses, and check for usable OCSP info
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
)
203 ocsp_response_t
*response
;
204 time_t revocation
, this_update
, next_update
, valid_until
;
206 bool revoked
= FALSE
;
208 response
= (ocsp_response_t
*)cand
;
210 /* check ocsp signature */
211 if (!verify_ocsp(response
, &issuer
->interface
))
216 /* check if response contains our certificate */
217 switch (response
->get_status(response
, subject
, issuer
, &revocation
, &reason
,
218 &this_update
, &next_update
))
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
);
226 case VALIDATION_GOOD
:
227 /* results in either good or stale */
230 case VALIDATION_FAILED
:
231 /* candidate unusable, does not contain our cert */
232 DBG1(DBG_CFG
, " ocsp response contains no status on our certificate");
237 /* select the better of the two responses */
238 if (best
== NULL
|| certificate_is_newer(cand
, best
))
242 if (best
->get_validity(best
, NULL
, NULL
, &valid_until
))
244 DBG1(DBG_CFG
, " ocsp response is valid: until %T",
245 &valid_until
, FALSE
);
246 *valid
= VALIDATION_GOOD
;
248 { /* cache non-stale only, stale certs get refetched */
249 lib
->credmgr
->cache_cert(lib
->credmgr
, best
);
254 DBG1(DBG_CFG
, " ocsp response is stale: since %T",
255 &valid_until
, FALSE
);
256 *valid
= VALIDATION_STALE
;
261 *valid
= VALIDATION_STALE
;
265 { /* revoked always counts, even if stale */
266 *valid
= VALIDATION_REVOKED
;
272 * validate a x509 certificate using OCSP
274 static cert_validation_t
check_ocsp(x509_t
*subject
, x509_t
*issuer
,
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;
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
, ¤t
))
290 current
->get_ref(current
);
291 best
= get_better_ocsp(current
, best
, subject
, issuer
, &valid
, FALSE
);
292 if (best
&& valid
!= VALIDATION_STALE
)
294 DBG1(DBG_CFG
, " using cached ocsp response");
298 enumerator
->destroy(enumerator
);
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
))
305 keyid
= identification_create_from_encoding(ID_KEY_ID
, chunk
);
307 /** fetch from configured OCSP responder URLs */
308 if (keyid
&& valid
!= VALIDATION_GOOD
&& valid
!= VALIDATION_REVOKED
)
310 enumerator
= lib
->credmgr
->create_cdp_enumerator(lib
->credmgr
,
311 CERT_X509_OCSP_RESPONSE
, keyid
);
312 while (enumerator
->enumerate(enumerator
, &uri
))
314 current
= fetch_ocsp(uri
, &subject
->interface
, &issuer
->interface
);
317 best
= get_better_ocsp(current
, best
, subject
, issuer
,
319 if (best
&& valid
!= VALIDATION_STALE
)
325 enumerator
->destroy(enumerator
);
330 /* fallback to URL fetching from subject certificate's URIs */
331 if (valid
!= VALIDATION_GOOD
&& valid
!= VALIDATION_REVOKED
)
333 enumerator
= subject
->create_ocsp_uri_enumerator(subject
);
334 while (enumerator
->enumerate(enumerator
, &uri
))
336 current
= fetch_ocsp(uri
, &subject
->interface
, &issuer
->interface
);
339 best
= get_better_ocsp(current
, best
, subject
, issuer
,
341 if (best
&& valid
!= VALIDATION_STALE
)
347 enumerator
->destroy(enumerator
);
349 /* an uri was found, but no result. switch validation state to failed */
350 if (valid
== VALIDATION_SKIPPED
&& uri
)
352 valid
= VALIDATION_FAILED
;
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
);
367 * fetch a CRL from an URL
369 static certificate_t
* fetch_crl(char *url
)
374 DBG1(DBG_CFG
, " fetching crl from '%s' ...", url
);
375 if (lib
->fetcher
->fetch(lib
->fetcher
, url
, &chunk
, FETCH_END
) != SUCCESS
)
377 DBG1(DBG_CFG
, "crl fetching failed");
380 crl
= lib
->creds
->create(lib
->creds
, CRED_CERTIFICATE
, CERT_X509_CRL
,
381 BUILD_BLOB_PEM
, chunk
, BUILD_END
);
385 DBG1(DBG_CFG
, "crl fetched successfully but parsing failed");
392 * check the signature of an CRL
394 static bool verify_crl(certificate_t
*crl
)
396 certificate_t
*issuer
;
397 enumerator_t
*enumerator
;
398 bool verified
= FALSE
;
400 enumerator
= lib
->credmgr
->create_trusted_enumerator(lib
->credmgr
,
401 KEY_ANY
, crl
->get_issuer(crl
), FALSE
);
402 while (enumerator
->enumerate(enumerator
, &issuer
, NULL
))
404 if (lib
->credmgr
->issued_by(lib
->credmgr
, crl
, issuer
, NULL
))
406 DBG1(DBG_CFG
, " crl correctly signed by \"%Y\"",
407 issuer
->get_subject(issuer
));
412 enumerator
->destroy(enumerator
);
418 * Report the given CRL's validity and cache it if valid and requested
420 static bool is_crl_valid(certificate_t
*crl
, bool cache
)
424 if (crl
->get_validity(crl
, NULL
, NULL
, &valid_until
))
426 DBG1(DBG_CFG
, " crl is valid: until %T", &valid_until
, FALSE
);
429 lib
->credmgr
->cache_cert(lib
->credmgr
, crl
);
433 DBG1(DBG_CFG
, " crl is stale: since %T", &valid_until
, FALSE
);
438 * Get the better of two CRLs, and check for usable CRL info
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
)
444 enumerator_t
*enumerator
;
447 chunk_t subject_serial
, serial
;
448 crl_t
*crl
= (crl_t
*)cand
;
452 if (!crl
->is_delta_crl(crl
, &serial
) ||
453 !chunk_equals(serial
, base
->get_serial(base
)))
461 if (crl
->is_delta_crl(crl
, NULL
))
468 /* check CRL signature */
469 if (!verify_crl(cand
))
471 DBG1(DBG_CFG
, "crl response verification failed");
476 subject_serial
= chunk_skip_zero(subject
->get_serial(subject
));
477 enumerator
= crl
->create_enumerator(crl
);
478 while (enumerator
->enumerate(enumerator
, &serial
, &revocation
, &reason
))
480 if (chunk_equals(subject_serial
, chunk_skip_zero(serial
)))
482 if (reason
!= CRL_REASON_CERTIFICATE_HOLD
)
484 *valid
= VALIDATION_REVOKED
;
488 /* if the cert is on hold, a newer CRL might not contain it */
489 *valid
= VALIDATION_ON_HOLD
;
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
);
499 enumerator
->destroy(enumerator
);
501 /* select the better of the two CRLs */
502 if (best
== NULL
|| crl_is_newer(crl
, (crl_t
*)best
))
506 if (is_crl_valid(best
, cache
))
508 *valid
= VALIDATION_GOOD
;
512 *valid
= VALIDATION_STALE
;
517 *valid
= VALIDATION_STALE
;
524 * Find or fetch a certificate for a given crlIssuer
526 static cert_validation_t
find_crl(x509_t
*subject
, identification_t
*issuer
,
527 crl_t
*base
, certificate_t
**best
,
530 cert_validation_t valid
= VALIDATION_SKIPPED
;
531 enumerator_t
*enumerator
;
532 certificate_t
*current
;
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
, ¤t
))
540 current
->get_ref(current
);
541 *best
= get_better_crl(current
, *best
, subject
, &valid
, FALSE
, base
);
542 if (*best
&& valid
!= VALIDATION_STALE
)
544 DBG1(DBG_CFG
, " using cached crl");
548 enumerator
->destroy(enumerator
);
550 /* fallback to fetching crls from credential sets cdps */
551 if (!base
&& valid
!= VALIDATION_GOOD
&& valid
!= VALIDATION_REVOKED
)
553 enumerator
= lib
->credmgr
->create_cdp_enumerator(lib
->credmgr
,
554 CERT_X509_CRL
, issuer
);
555 while (enumerator
->enumerate(enumerator
, &uri
))
558 current
= fetch_crl(uri
);
561 if (!current
->has_issuer(current
, issuer
))
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
);
568 *best
= get_better_crl(current
, *best
, subject
,
570 if (*best
&& valid
!= VALIDATION_STALE
)
576 enumerator
->destroy(enumerator
);
582 * Look for a delta CRL for a given base CRL
584 static cert_validation_t
check_delta_crl(x509_t
*subject
, x509_t
*issuer
,
585 crl_t
*base
, cert_validation_t base_valid
)
587 cert_validation_t valid
= VALIDATION_SKIPPED
;
588 certificate_t
*best
= NULL
, *current
;
589 enumerator_t
*enumerator
;
590 identification_t
*id
;
595 /* find cached delta CRL via subjectKeyIdentifier */
596 chunk
= issuer
->get_subjectKeyIdentifier(issuer
);
599 id
= identification_create_from_encoding(ID_KEY_ID
, chunk
);
600 valid
= find_crl(subject
, id
, base
, &best
, &uri
);
604 /* find delta CRL by CRLIssuer */
605 enumerator
= subject
->create_crl_uri_enumerator(subject
);
606 while (valid
!= VALIDATION_GOOD
&& valid
!= VALIDATION_REVOKED
&&
607 enumerator
->enumerate(enumerator
, &cdp
))
611 valid
= find_crl(subject
, cdp
->issuer
, base
, &best
, &uri
);
614 enumerator
->destroy(enumerator
);
616 /* fetch from URIs found in Freshest CRL extension */
617 enumerator
= base
->create_delta_crl_uri_enumerator(base
);
618 while (valid
!= VALIDATION_GOOD
&& valid
!= VALIDATION_REVOKED
&&
619 enumerator
->enumerate(enumerator
, &cdp
))
621 current
= fetch_crl(cdp
->uri
);
624 if (cdp
->issuer
&& !current
->has_issuer(current
, cdp
->issuer
))
626 DBG1(DBG_CFG
, "issuer of fetched delta CRL '%Y' does not match "
627 "certificates CRL issuer '%Y'",
628 current
->get_issuer(current
), cdp
->issuer
);
629 current
->destroy(current
);
632 best
= get_better_crl(current
, best
, subject
, &valid
, TRUE
, base
);
633 if (best
&& valid
!= VALIDATION_STALE
)
639 enumerator
->destroy(enumerator
);
650 * validate a x509 certificate using CRL
652 static cert_validation_t
check_crl(x509_t
*subject
, x509_t
*issuer
,
655 cert_validation_t valid
= VALIDATION_SKIPPED
;
656 certificate_t
*best
= NULL
;
657 identification_t
*id
;
659 bool uri_found
= FALSE
;
660 certificate_t
*current
;
661 enumerator_t
*enumerator
;
664 /* use issuers subjectKeyIdentifier to find a cached CRL / fetch from CDP */
665 chunk
= issuer
->get_subjectKeyIdentifier(issuer
);
668 id
= identification_create_from_encoding(ID_KEY_ID
, chunk
);
669 valid
= find_crl(subject
, id
, NULL
, &best
, &uri_found
);
673 /* find a cached CRL or fetch via configured CDP via CRLIssuer */
674 enumerator
= subject
->create_crl_uri_enumerator(subject
);
675 while (valid
!= VALIDATION_GOOD
&& valid
!= VALIDATION_REVOKED
&&
676 enumerator
->enumerate(enumerator
, &cdp
))
680 valid
= find_crl(subject
, cdp
->issuer
, NULL
, &best
, &uri_found
);
683 enumerator
->destroy(enumerator
);
685 /* fallback to fetching CRLs from CDPs found in subjects certificate */
686 if (valid
!= VALIDATION_GOOD
&& valid
!= VALIDATION_REVOKED
)
688 enumerator
= subject
->create_crl_uri_enumerator(subject
);
689 while (enumerator
->enumerate(enumerator
, &cdp
))
692 current
= fetch_crl(cdp
->uri
);
695 if (cdp
->issuer
&& !current
->has_issuer(current
, cdp
->issuer
))
697 DBG1(DBG_CFG
, "issuer of fetched CRL '%Y' does not match "
698 "certificates CRL issuer '%Y'",
699 current
->get_issuer(current
), cdp
->issuer
);
700 current
->destroy(current
);
703 best
= get_better_crl(current
, best
, subject
, &valid
,
705 if (best
&& valid
!= VALIDATION_STALE
)
711 enumerator
->destroy(enumerator
);
714 /* look for delta CRLs */
715 if (best
&& (valid
== VALIDATION_GOOD
|| valid
== VALIDATION_STALE
))
717 valid
= check_delta_crl(subject
, issuer
, (crl_t
*)best
, valid
);
720 /* an uri was found, but no result. switch validation state to failed */
721 if (valid
== VALIDATION_SKIPPED
&& uri_found
)
723 valid
= VALIDATION_FAILED
;
727 if (valid
== VALIDATION_SKIPPED
)
728 { /* if we skipped CRL validation, we use the result of OCSP for
729 * constraint checking */
730 auth
->add(auth
, AUTH_RULE_CRL_VALIDATION
,
731 auth
->get(auth
, AUTH_RULE_OCSP_VALIDATION
));
735 auth
->add(auth
, AUTH_RULE_CRL_VALIDATION
, valid
);
742 METHOD(cert_validator_t
, validate
, bool,
743 private_revocation_validator_t
*this, certificate_t
*subject
,
744 certificate_t
*issuer
, bool online
, u_int pathlen
, bool anchor
,
747 if (online
&& (this->enable_ocsp
|| this->enable_crl
) &&
748 subject
->get_type(subject
) == CERT_X509
&&
749 issuer
->get_type(issuer
) == CERT_X509
)
751 DBG1(DBG_CFG
, "checking certificate status of \"%Y\"",
752 subject
->get_subject(subject
));
754 if (this->enable_ocsp
)
756 switch (check_ocsp((x509_t
*)subject
, (x509_t
*)issuer
,
757 pathlen
? NULL
: auth
))
759 case VALIDATION_GOOD
:
760 DBG1(DBG_CFG
, "certificate status is good");
762 case VALIDATION_REVOKED
:
763 case VALIDATION_ON_HOLD
:
764 /* has already been logged */
765 lib
->credmgr
->call_hook(lib
->credmgr
, CRED_HOOK_REVOKED
,
768 case VALIDATION_SKIPPED
:
769 DBG2(DBG_CFG
, "ocsp check skipped, no ocsp found");
771 case VALIDATION_STALE
:
772 DBG1(DBG_CFG
, "ocsp information stale, fallback to crl");
774 case VALIDATION_FAILED
:
775 DBG1(DBG_CFG
, "ocsp check failed, fallback to crl");
780 if (this->enable_crl
)
782 switch (check_crl((x509_t
*)subject
, (x509_t
*)issuer
,
783 pathlen
? NULL
: auth
))
785 case VALIDATION_GOOD
:
786 DBG1(DBG_CFG
, "certificate status is good");
788 case VALIDATION_REVOKED
:
789 case VALIDATION_ON_HOLD
:
790 /* has already been logged */
791 lib
->credmgr
->call_hook(lib
->credmgr
, CRED_HOOK_REVOKED
,
794 case VALIDATION_FAILED
:
795 case VALIDATION_SKIPPED
:
796 DBG1(DBG_CFG
, "certificate status is not available");
798 case VALIDATION_STALE
:
799 DBG1(DBG_CFG
, "certificate status is unknown, crl is stale");
804 lib
->credmgr
->call_hook(lib
->credmgr
, CRED_HOOK_VALIDATION_FAILED
,
810 METHOD(revocation_validator_t
, destroy
, void,
811 private_revocation_validator_t
*this)
819 revocation_validator_t
*revocation_validator_create()
821 private_revocation_validator_t
*this;
825 .validator
.validate
= _validate
,
828 .enable_ocsp
= lib
->settings
->get_bool(lib
->settings
,
829 "%s.plugins.revocation.enable_ocsp", TRUE
, lib
->ns
),
830 .enable_crl
= lib
->settings
->get_bool(lib
->settings
,
831 "%s.plugins.revocation.enable_crl", TRUE
, lib
->ns
),
834 if (!this->enable_ocsp
)
836 DBG1(DBG_LIB
, "all OCSP validation disabled");
838 if (!this->enable_crl
)
840 DBG1(DBG_LIB
, "all CRL validation disabled");
842 return &this->public;