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;
44 static certificate_t
*fetch_ocsp(char *url
, certificate_t
*subject
,
45 certificate_t
*issuer
)
47 certificate_t
*request
, *response
;
48 chunk_t send
, receive
;
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
);
57 DBG1(DBG_CFG
, "generating ocsp request failed");
61 if (!request
->get_encoding(request
, CERT_ASN1_DER
, &send
))
63 DBG1(DBG_CFG
, "encoding ocsp request failed");
64 request
->destroy(request
);
67 request
->destroy(request
);
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
)
75 DBG1(DBG_CFG
, "ocsp request to %s failed", url
);
81 response
= lib
->creds
->create(lib
->creds
,
82 CRED_CERTIFICATE
, CERT_X509_OCSP_RESPONSE
,
83 BUILD_BLOB_ASN1_DER
, receive
, BUILD_END
);
87 DBG1(DBG_CFG
, "parsing ocsp response failed");
94 * check the signature of an OCSP response
96 static bool verify_ocsp(ocsp_response_t
*response
, certificate_t
*ca
)
98 certificate_t
*issuer
, *subject
;
99 identification_t
*responder
;
100 ocsp_response_wrapper_t
*wrapper
;
101 enumerator_t
*enumerator
;
103 bool verified
= FALSE
, found
= FALSE
;
105 wrapper
= ocsp_response_wrapper_create((ocsp_response_t
*)response
);
106 lib
->credmgr
->add_local_set(lib
->credmgr
, &wrapper
->set
, FALSE
);
108 subject
= &response
->certificate
;
109 responder
= subject
->get_issuer(subject
);
111 /* check OCSP response using CA or directly delegated OCSP signer */
112 enumerator
= lib
->credmgr
->create_cert_enumerator(lib
->credmgr
, CERT_X509
,
113 KEY_ANY
, responder
, FALSE
);
114 while (enumerator
->enumerate(enumerator
, &issuer
))
116 x509
= (x509_t
*)issuer
;
117 if (!issuer
->get_validity(issuer
, NULL
, NULL
, NULL
))
118 { /* OCSP signer currently invalid */
122 if (!ca
->equals(ca
, issuer
))
123 { /* delegated OCSP signer? */
124 if (!lib
->credmgr
->issued_by(lib
->credmgr
, issuer
, ca
, NULL
))
125 { /* OCSP response not signed by CA, nor delegated OCSP signer */
128 if (!(x509
->get_flags(x509
) & X509_OCSP_SIGNER
))
129 { /* delegated OCSP signer does not have OCSP signer flag */
133 if (lib
->credmgr
->issued_by(lib
->credmgr
, subject
, issuer
, NULL
))
135 DBG1(DBG_CFG
, " ocsp response correctly signed by \"%Y\"",
136 issuer
->get_subject(issuer
));
140 DBG1(DBG_CFG
, "ocsp response verification failed, "
141 "invalid signature");
143 enumerator
->destroy(enumerator
);
147 /* as fallback, use any locally installed OCSP signer certificate */
148 enumerator
= lib
->credmgr
->create_cert_enumerator(lib
->credmgr
,
149 CERT_X509
, KEY_ANY
, responder
, TRUE
);
150 while (enumerator
->enumerate(enumerator
, &issuer
))
152 x509
= (x509_t
*)issuer
;
153 /* while issued_by() accepts both OCSP signer or CA basic
154 * constraint flags to verify OCSP responses, unrelated but trusted
155 * OCSP signers must explicitly have the OCSP signer flag set. */
156 if ((x509
->get_flags(x509
) & X509_OCSP_SIGNER
) &&
157 issuer
->get_validity(issuer
, NULL
, NULL
, NULL
))
160 if (lib
->credmgr
->issued_by(lib
->credmgr
, subject
, issuer
, NULL
))
162 DBG1(DBG_CFG
, " ocsp response correctly signed by \"%Y\"",
163 issuer
->get_subject(issuer
));
167 DBG1(DBG_CFG
, "ocsp response verification failed, "
168 "invalid signature");
171 enumerator
->destroy(enumerator
);
174 lib
->credmgr
->remove_local_set(lib
->credmgr
, &wrapper
->set
);
175 wrapper
->destroy(wrapper
);
179 DBG1(DBG_CFG
, "ocsp response verification failed, "
180 "no signer certificate '%Y' found", responder
);
186 * Get the better of two OCSP responses, and check for usable OCSP info
188 static certificate_t
*get_better_ocsp(certificate_t
*cand
, certificate_t
*best
,
189 x509_t
*subject
, x509_t
*issuer
,
190 cert_validation_t
*valid
, bool cache
)
192 ocsp_response_t
*response
;
193 time_t revocation
, this_update
, next_update
, valid_until
;
195 bool revoked
= FALSE
;
197 response
= (ocsp_response_t
*)cand
;
199 /* check ocsp signature */
200 if (!verify_ocsp(response
, &issuer
->interface
))
205 /* check if response contains our certificate */
206 switch (response
->get_status(response
, subject
, issuer
, &revocation
, &reason
,
207 &this_update
, &next_update
))
209 case VALIDATION_REVOKED
:
210 /* subject has been revoked by a valid OCSP response */
211 DBG1(DBG_CFG
, "certificate was revoked on %T, reason: %N",
212 &revocation
, TRUE
, crl_reason_names
, reason
);
215 case VALIDATION_GOOD
:
216 /* results in either good or stale */
219 case VALIDATION_FAILED
:
220 /* candidate unusable, does not contain our cert */
221 DBG1(DBG_CFG
, " ocsp response contains no status on our certificate");
226 /* select the better of the two responses */
227 if (best
== NULL
|| certificate_is_newer(cand
, best
))
231 if (best
->get_validity(best
, NULL
, NULL
, &valid_until
))
233 DBG1(DBG_CFG
, " ocsp response is valid: until %T",
234 &valid_until
, FALSE
);
235 *valid
= VALIDATION_GOOD
;
237 { /* cache non-stale only, stale certs get refetched */
238 lib
->credmgr
->cache_cert(lib
->credmgr
, best
);
243 DBG1(DBG_CFG
, " ocsp response is stale: since %T",
244 &valid_until
, FALSE
);
245 *valid
= VALIDATION_STALE
;
250 *valid
= VALIDATION_STALE
;
254 { /* revoked always counts, even if stale */
255 *valid
= VALIDATION_REVOKED
;
261 * validate a x509 certificate using OCSP
263 static cert_validation_t
check_ocsp(x509_t
*subject
, x509_t
*issuer
,
266 enumerator_t
*enumerator
;
267 cert_validation_t valid
= VALIDATION_SKIPPED
;
268 certificate_t
*best
= NULL
, *current
;
269 identification_t
*keyid
= NULL
;
270 public_key_t
*public;
274 /** lookup cache for valid OCSP responses */
275 enumerator
= lib
->credmgr
->create_cert_enumerator(lib
->credmgr
,
276 CERT_X509_OCSP_RESPONSE
, KEY_ANY
, NULL
, FALSE
);
277 while (enumerator
->enumerate(enumerator
, ¤t
))
279 current
->get_ref(current
);
280 best
= get_better_ocsp(current
, best
, subject
, issuer
, &valid
, FALSE
);
281 if (best
&& valid
!= VALIDATION_STALE
)
283 DBG1(DBG_CFG
, " using cached ocsp response");
287 enumerator
->destroy(enumerator
);
289 /* derive the authorityKeyIdentifier from the issuer's public key */
290 current
= &issuer
->interface
;
291 public = current
->get_public_key(current
);
292 if (public && public->get_fingerprint(public, KEYID_PUBKEY_SHA1
, &chunk
))
294 keyid
= identification_create_from_encoding(ID_KEY_ID
, chunk
);
296 /** fetch from configured OCSP responder URLs */
297 if (keyid
&& valid
!= VALIDATION_GOOD
&& valid
!= VALIDATION_REVOKED
)
299 enumerator
= lib
->credmgr
->create_cdp_enumerator(lib
->credmgr
,
300 CERT_X509_OCSP_RESPONSE
, keyid
);
301 while (enumerator
->enumerate(enumerator
, &uri
))
303 current
= fetch_ocsp(uri
, &subject
->interface
, &issuer
->interface
);
306 best
= get_better_ocsp(current
, best
, subject
, issuer
,
308 if (best
&& valid
!= VALIDATION_STALE
)
314 enumerator
->destroy(enumerator
);
319 /* fallback to URL fetching from subject certificate's URIs */
320 if (valid
!= VALIDATION_GOOD
&& valid
!= VALIDATION_REVOKED
)
322 enumerator
= subject
->create_ocsp_uri_enumerator(subject
);
323 while (enumerator
->enumerate(enumerator
, &uri
))
325 current
= fetch_ocsp(uri
, &subject
->interface
, &issuer
->interface
);
328 best
= get_better_ocsp(current
, best
, subject
, issuer
,
330 if (best
&& valid
!= VALIDATION_STALE
)
336 enumerator
->destroy(enumerator
);
338 /* an uri was found, but no result. switch validation state to failed */
339 if (valid
== VALIDATION_SKIPPED
&& uri
)
341 valid
= VALIDATION_FAILED
;
345 auth
->add(auth
, AUTH_RULE_OCSP_VALIDATION
, valid
);
346 if (valid
== VALIDATION_GOOD
)
347 { /* successful OCSP check fulfills also CRL constraint */
348 auth
->add(auth
, AUTH_RULE_CRL_VALIDATION
, VALIDATION_GOOD
);
356 * fetch a CRL from an URL
358 static certificate_t
* fetch_crl(char *url
)
363 DBG1(DBG_CFG
, " fetching crl from '%s' ...", url
);
364 if (lib
->fetcher
->fetch(lib
->fetcher
, url
, &chunk
, FETCH_END
) != SUCCESS
)
366 DBG1(DBG_CFG
, "crl fetching failed");
369 crl
= lib
->creds
->create(lib
->creds
, CRED_CERTIFICATE
, CERT_X509_CRL
,
370 BUILD_BLOB_ASN1_DER
, chunk
, BUILD_END
);
374 DBG1(DBG_CFG
, "crl fetched successfully but parsing failed");
381 * check the signature of an CRL
383 static bool verify_crl(certificate_t
*crl
)
385 certificate_t
*issuer
;
386 enumerator_t
*enumerator
;
387 bool verified
= FALSE
;
389 enumerator
= lib
->credmgr
->create_trusted_enumerator(lib
->credmgr
,
390 KEY_ANY
, crl
->get_issuer(crl
), FALSE
);
391 while (enumerator
->enumerate(enumerator
, &issuer
, NULL
))
393 if (lib
->credmgr
->issued_by(lib
->credmgr
, crl
, issuer
, NULL
))
395 DBG1(DBG_CFG
, " crl correctly signed by \"%Y\"",
396 issuer
->get_subject(issuer
));
401 enumerator
->destroy(enumerator
);
407 * Get the better of two CRLs, and check for usable CRL info
409 static certificate_t
*get_better_crl(certificate_t
*cand
, certificate_t
*best
,
410 x509_t
*subject
, cert_validation_t
*valid
,
411 bool cache
, crl_t
*base
)
413 enumerator_t
*enumerator
;
414 time_t revocation
, valid_until
;
417 crl_t
*crl
= (crl_t
*)cand
;
421 if (!crl
->is_delta_crl(crl
, &serial
) ||
422 !chunk_equals(serial
, base
->get_serial(base
)))
430 if (crl
->is_delta_crl(crl
, NULL
))
437 /* check CRL signature */
438 if (!verify_crl(cand
))
440 DBG1(DBG_CFG
, "crl response verification failed");
445 enumerator
= crl
->create_enumerator(crl
);
446 while (enumerator
->enumerate(enumerator
, &serial
, &revocation
, &reason
))
448 if (chunk_equals(serial
, subject
->get_serial(subject
)))
450 DBG1(DBG_CFG
, "certificate was revoked on %T, reason: %N",
451 &revocation
, TRUE
, crl_reason_names
, reason
);
452 if (reason
!= CRL_REASON_CERTIFICATE_HOLD
)
454 *valid
= VALIDATION_REVOKED
;
458 /* if the cert is on hold, a newer CRL might not contain it */
459 *valid
= VALIDATION_ON_HOLD
;
461 enumerator
->destroy(enumerator
);
466 enumerator
->destroy(enumerator
);
468 /* select the better of the two CRLs */
469 if (best
== NULL
|| crl_is_newer(crl
, (crl_t
*)best
))
473 if (best
->get_validity(best
, NULL
, NULL
, &valid_until
))
475 DBG1(DBG_CFG
, " crl is valid: until %T", &valid_until
, FALSE
);
476 *valid
= VALIDATION_GOOD
;
478 { /* we cache non-stale crls only, as a stale crls are refetched */
479 lib
->credmgr
->cache_cert(lib
->credmgr
, best
);
484 DBG1(DBG_CFG
, " crl is stale: since %T", &valid_until
, FALSE
);
485 *valid
= VALIDATION_STALE
;
490 *valid
= VALIDATION_STALE
;
497 * Find or fetch a certificate for a given crlIssuer
499 static cert_validation_t
find_crl(x509_t
*subject
, identification_t
*issuer
,
500 crl_t
*base
, certificate_t
**best
,
503 cert_validation_t valid
= VALIDATION_SKIPPED
;
504 enumerator_t
*enumerator
;
505 certificate_t
*current
;
508 /* find a cached (delta) crl */
509 enumerator
= lib
->credmgr
->create_cert_enumerator(lib
->credmgr
,
510 CERT_X509_CRL
, KEY_ANY
, issuer
, FALSE
);
511 while (enumerator
->enumerate(enumerator
, ¤t
))
513 current
->get_ref(current
);
514 *best
= get_better_crl(current
, *best
, subject
, &valid
, FALSE
, base
);
515 if (*best
&& valid
!= VALIDATION_STALE
)
517 DBG1(DBG_CFG
, " using cached crl");
521 enumerator
->destroy(enumerator
);
523 /* fallback to fetching crls from credential sets cdps */
524 if (!base
&& valid
!= VALIDATION_GOOD
&& valid
!= VALIDATION_REVOKED
)
526 enumerator
= lib
->credmgr
->create_cdp_enumerator(lib
->credmgr
,
527 CERT_X509_CRL
, issuer
);
528 while (enumerator
->enumerate(enumerator
, &uri
))
531 current
= fetch_crl(uri
);
534 if (!current
->has_issuer(current
, issuer
))
536 DBG1(DBG_CFG
, "issuer of fetched CRL '%Y' does not match CRL "
537 "issuer '%Y'", current
->get_issuer(current
), issuer
);
538 current
->destroy(current
);
541 *best
= get_better_crl(current
, *best
, subject
,
543 if (*best
&& valid
!= VALIDATION_STALE
)
549 enumerator
->destroy(enumerator
);
555 * Look for a delta CRL for a given base CRL
557 static cert_validation_t
check_delta_crl(x509_t
*subject
, x509_t
*issuer
,
558 crl_t
*base
, cert_validation_t base_valid
)
560 cert_validation_t valid
= VALIDATION_SKIPPED
;
561 certificate_t
*best
= NULL
, *current
;
562 enumerator_t
*enumerator
;
563 identification_t
*id
;
568 /* find cached delta CRL via subjectKeyIdentifier */
569 chunk
= issuer
->get_subjectKeyIdentifier(issuer
);
572 id
= identification_create_from_encoding(ID_KEY_ID
, chunk
);
573 valid
= find_crl(subject
, id
, base
, &best
, &uri
);
577 /* find delta CRL by CRLIssuer */
578 enumerator
= subject
->create_crl_uri_enumerator(subject
);
579 while (valid
!= VALIDATION_GOOD
&& valid
!= VALIDATION_REVOKED
&&
580 enumerator
->enumerate(enumerator
, &cdp
))
584 valid
= find_crl(subject
, cdp
->issuer
, base
, &best
, &uri
);
587 enumerator
->destroy(enumerator
);
589 /* fetch from URIs found in Freshest CRL extension */
590 enumerator
= base
->create_delta_crl_uri_enumerator(base
);
591 while (valid
!= VALIDATION_GOOD
&& valid
!= VALIDATION_REVOKED
&&
592 enumerator
->enumerate(enumerator
, &cdp
))
594 current
= fetch_crl(cdp
->uri
);
597 if (cdp
->issuer
&& !current
->has_issuer(current
, cdp
->issuer
))
599 DBG1(DBG_CFG
, "issuer of fetched delta CRL '%Y' does not match "
600 "certificates CRL issuer '%Y'",
601 current
->get_issuer(current
), cdp
->issuer
);
602 current
->destroy(current
);
605 best
= get_better_crl(current
, best
, subject
, &valid
, TRUE
, base
);
606 if (best
&& valid
!= VALIDATION_STALE
)
612 enumerator
->destroy(enumerator
);
623 * validate a x509 certificate using CRL
625 static cert_validation_t
check_crl(x509_t
*subject
, x509_t
*issuer
,
628 cert_validation_t valid
= VALIDATION_SKIPPED
;
629 certificate_t
*best
= NULL
;
630 identification_t
*id
;
632 bool uri_found
= FALSE
;
633 certificate_t
*current
;
634 enumerator_t
*enumerator
;
637 /* use issuers subjectKeyIdentifier to find a cached CRL / fetch from CDP */
638 chunk
= issuer
->get_subjectKeyIdentifier(issuer
);
641 id
= identification_create_from_encoding(ID_KEY_ID
, chunk
);
642 valid
= find_crl(subject
, id
, NULL
, &best
, &uri_found
);
646 /* find a cached CRL or fetch via configured CDP via CRLIssuer */
647 enumerator
= subject
->create_crl_uri_enumerator(subject
);
648 while (valid
!= VALIDATION_GOOD
&& valid
!= VALIDATION_REVOKED
&&
649 enumerator
->enumerate(enumerator
, &cdp
))
653 valid
= find_crl(subject
, cdp
->issuer
, NULL
, &best
, &uri_found
);
656 enumerator
->destroy(enumerator
);
658 /* fallback to fetching CRLs from CDPs found in subjects certificate */
659 if (valid
!= VALIDATION_GOOD
&& valid
!= VALIDATION_REVOKED
)
661 enumerator
= subject
->create_crl_uri_enumerator(subject
);
662 while (enumerator
->enumerate(enumerator
, &cdp
))
665 current
= fetch_crl(cdp
->uri
);
668 if (cdp
->issuer
&& !current
->has_issuer(current
, cdp
->issuer
))
670 DBG1(DBG_CFG
, "issuer of fetched CRL '%Y' does not match "
671 "certificates CRL issuer '%Y'",
672 current
->get_issuer(current
), cdp
->issuer
);
673 current
->destroy(current
);
676 best
= get_better_crl(current
, best
, subject
, &valid
,
678 if (best
&& valid
!= VALIDATION_STALE
)
684 enumerator
->destroy(enumerator
);
687 /* look for delta CRLs */
688 if (best
&& (valid
== VALIDATION_GOOD
|| valid
== VALIDATION_STALE
))
690 valid
= check_delta_crl(subject
, issuer
, (crl_t
*)best
, valid
);
693 /* an uri was found, but no result. switch validation state to failed */
694 if (valid
== VALIDATION_SKIPPED
&& uri_found
)
696 valid
= VALIDATION_FAILED
;
700 if (valid
== VALIDATION_SKIPPED
)
701 { /* if we skipped CRL validation, we use the result of OCSP for
702 * constraint checking */
703 auth
->add(auth
, AUTH_RULE_CRL_VALIDATION
,
704 auth
->get(auth
, AUTH_RULE_OCSP_VALIDATION
));
708 auth
->add(auth
, AUTH_RULE_CRL_VALIDATION
, valid
);
715 METHOD(cert_validator_t
, validate
, bool,
716 private_revocation_validator_t
*this, certificate_t
*subject
,
717 certificate_t
*issuer
, bool online
, u_int pathlen
, bool anchor
,
720 if (subject
->get_type(subject
) == CERT_X509
&&
721 issuer
->get_type(issuer
) == CERT_X509
&&
724 DBG1(DBG_CFG
, "checking certificate status of \"%Y\"",
725 subject
->get_subject(subject
));
726 switch (check_ocsp((x509_t
*)subject
, (x509_t
*)issuer
,
727 pathlen ? NULL
: auth
))
729 case VALIDATION_GOOD
:
730 DBG1(DBG_CFG
, "certificate status is good");
732 case VALIDATION_REVOKED
:
733 case VALIDATION_ON_HOLD
:
734 /* has already been logged */
735 lib
->credmgr
->call_hook(lib
->credmgr
, CRED_HOOK_REVOKED
,
738 case VALIDATION_SKIPPED
:
739 DBG2(DBG_CFG
, "ocsp check skipped, no ocsp found");
741 case VALIDATION_STALE
:
742 DBG1(DBG_CFG
, "ocsp information stale, fallback to crl");
744 case VALIDATION_FAILED
:
745 DBG1(DBG_CFG
, "ocsp check failed, fallback to crl");
748 switch (check_crl((x509_t
*)subject
, (x509_t
*)issuer
,
749 pathlen ? NULL
: auth
))
751 case VALIDATION_GOOD
:
752 DBG1(DBG_CFG
, "certificate status is good");
754 case VALIDATION_REVOKED
:
755 case VALIDATION_ON_HOLD
:
756 /* has already been logged */
757 lib
->credmgr
->call_hook(lib
->credmgr
, CRED_HOOK_REVOKED
,
760 case VALIDATION_FAILED
:
761 case VALIDATION_SKIPPED
:
762 DBG1(DBG_CFG
, "certificate status is not available");
764 case VALIDATION_STALE
:
765 DBG1(DBG_CFG
, "certificate status is unknown, crl is stale");
768 lib
->credmgr
->call_hook(lib
->credmgr
, CRED_HOOK_VALIDATION_FAILED
,
774 METHOD(revocation_validator_t
, destroy
, void,
775 private_revocation_validator_t
*this)
783 revocation_validator_t
*revocation_validator_create()
785 private_revocation_validator_t
*this;
789 .validator
.validate
= _validate
,
794 return &this->public;