revocation: Restrict OCSP signing to specific certificates
To avoid considering each cached OCSP response and evaluating its trustchain, we limit the certificates considered for OCSP signing to: - The issuing CA of the checked certificate - A directly delegated signer by the same CA, having the OCSP signer constraint - Any locally installed (trusted) certificate having the OCSP signer constraint The first two options cover the requirements from RFC 6960 2.6. For compatibility with non-conforming CAs, we allow the third option as exception, but require the installation of such certificates locally.
This commit is contained in:
@@ -93,35 +93,92 @@ static certificate_t *fetch_ocsp(char *url, certificate_t *subject,
|
|||||||
/**
|
/**
|
||||||
* check the signature of an OCSP response
|
* check the signature of an OCSP response
|
||||||
*/
|
*/
|
||||||
static bool verify_ocsp(ocsp_response_t *response)
|
static bool verify_ocsp(ocsp_response_t *response, certificate_t *ca)
|
||||||
{
|
{
|
||||||
certificate_t *issuer, *subject;
|
certificate_t *issuer, *subject;
|
||||||
identification_t *responder;
|
identification_t *responder;
|
||||||
ocsp_response_wrapper_t *wrapper;
|
ocsp_response_wrapper_t *wrapper;
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
bool verified = FALSE;
|
x509_t *x509;
|
||||||
|
bool verified = FALSE, found = FALSE;
|
||||||
|
|
||||||
wrapper = ocsp_response_wrapper_create((ocsp_response_t*)response);
|
wrapper = ocsp_response_wrapper_create((ocsp_response_t*)response);
|
||||||
lib->credmgr->add_local_set(lib->credmgr, &wrapper->set, FALSE);
|
lib->credmgr->add_local_set(lib->credmgr, &wrapper->set, FALSE);
|
||||||
|
|
||||||
subject = &response->certificate;
|
subject = &response->certificate;
|
||||||
responder = subject->get_issuer(subject);
|
responder = subject->get_issuer(subject);
|
||||||
enumerator = lib->credmgr->create_trusted_enumerator(lib->credmgr,
|
|
||||||
|
/* check OCSP response using CA or directly delegated OCSP signer */
|
||||||
|
enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr, CERT_X509,
|
||||||
KEY_ANY, responder, FALSE);
|
KEY_ANY, responder, FALSE);
|
||||||
while (enumerator->enumerate(enumerator, &issuer, NULL))
|
while (enumerator->enumerate(enumerator, &issuer))
|
||||||
{
|
{
|
||||||
|
x509 = (x509_t*)issuer;
|
||||||
|
if (!issuer->get_validity(issuer, NULL, NULL, NULL))
|
||||||
|
{ /* OCSP signer currently invalid */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
found = TRUE;
|
||||||
|
if (!ca->equals(ca, issuer))
|
||||||
|
{ /* delegated OCSP signer? */
|
||||||
|
if (!lib->credmgr->issued_by(lib->credmgr, issuer, ca, NULL))
|
||||||
|
{ /* OCSP response not signed by CA, nor delegated OCSP signer */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!(x509->get_flags(x509) & X509_OCSP_SIGNER))
|
||||||
|
{ /* delegated OCSP signer does not have OCSP signer flag */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (lib->credmgr->issued_by(lib->credmgr, subject, issuer, NULL))
|
if (lib->credmgr->issued_by(lib->credmgr, subject, issuer, NULL))
|
||||||
{
|
{
|
||||||
DBG1(DBG_CFG, " ocsp response correctly signed by \"%Y\"",
|
DBG1(DBG_CFG, " ocsp response correctly signed by \"%Y\"",
|
||||||
issuer->get_subject(issuer));
|
issuer->get_subject(issuer));
|
||||||
verified = TRUE;
|
verified = TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
DBG1(DBG_CFG, "ocsp response verification failed, "
|
||||||
|
"invalid signature");
|
||||||
}
|
}
|
||||||
enumerator->destroy(enumerator);
|
enumerator->destroy(enumerator);
|
||||||
|
|
||||||
|
if (!verified)
|
||||||
|
{
|
||||||
|
/* as fallback, use any locally installed OCSP signer certificate */
|
||||||
|
enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
|
||||||
|
CERT_X509, KEY_ANY, responder, TRUE);
|
||||||
|
while (enumerator->enumerate(enumerator, &issuer))
|
||||||
|
{
|
||||||
|
x509 = (x509_t*)issuer;
|
||||||
|
/* while issued_by() accepts both OCSP signer or CA basic
|
||||||
|
* constraint flags to verify OCSP responses, unrelated but trusted
|
||||||
|
* OCSP signers must explicitly have the OCSP signer flag set. */
|
||||||
|
if ((x509->get_flags(x509) & X509_OCSP_SIGNER) &&
|
||||||
|
issuer->get_validity(issuer, NULL, NULL, NULL))
|
||||||
|
{
|
||||||
|
found = TRUE;
|
||||||
|
if (lib->credmgr->issued_by(lib->credmgr, subject, issuer, NULL))
|
||||||
|
{
|
||||||
|
DBG1(DBG_CFG, " ocsp response correctly signed by \"%Y\"",
|
||||||
|
issuer->get_subject(issuer));
|
||||||
|
verified = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DBG1(DBG_CFG, "ocsp response verification failed, "
|
||||||
|
"invalid signature");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enumerator->destroy(enumerator);
|
||||||
|
}
|
||||||
|
|
||||||
lib->credmgr->remove_local_set(lib->credmgr, &wrapper->set);
|
lib->credmgr->remove_local_set(lib->credmgr, &wrapper->set);
|
||||||
wrapper->destroy(wrapper);
|
wrapper->destroy(wrapper);
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
DBG1(DBG_CFG, "ocsp response verification failed, "
|
||||||
|
"no signer certificate '%Y' found", responder);
|
||||||
|
}
|
||||||
return verified;
|
return verified;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,9 +197,8 @@ static certificate_t *get_better_ocsp(certificate_t *cand, certificate_t *best,
|
|||||||
response = (ocsp_response_t*)cand;
|
response = (ocsp_response_t*)cand;
|
||||||
|
|
||||||
/* check ocsp signature */
|
/* check ocsp signature */
|
||||||
if (!verify_ocsp(response))
|
if (!verify_ocsp(response, &issuer->interface))
|
||||||
{
|
{
|
||||||
DBG1(DBG_CFG, "ocsp response verification failed");
|
|
||||||
cand->destroy(cand);
|
cand->destroy(cand);
|
||||||
return best;
|
return best;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
moon:: cat /var/log/daemon.log::requesting ocsp status from::YES
|
moon:: cat /var/log/daemon.log::requesting ocsp status from::YES
|
||||||
moon:: cat /var/log/daemon.log::ocsp response verification failed::YES
|
moon:: cat /var/log/daemon.log::ocsp response verification failed, no signer::YES
|
||||||
moon:: cat /var/log/daemon.log::certificate status is not available::YES
|
moon:: cat /var/log/daemon.log::certificate status is not available::YES
|
||||||
moon:: cat /var/log/daemon.log::constraint check failed: RULE_CRL_VALIDATION is FAILED, but requires at least GOOD::YES
|
moon:: cat /var/log/daemon.log::constraint check failed: RULE_CRL_VALIDATION is FAILED, but requires at least GOOD::YES
|
||||||
moon:: ipsec status 2> /dev/null::rw.*ESTABLISHED::NO
|
moon:: ipsec status 2> /dev/null::rw.*ESTABLISHED::NO
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
moon:: cat /var/log/daemon.log::requesting ocsp status from::YES
|
moon:: cat /var/log/daemon.log::requesting ocsp status from::YES
|
||||||
moon:: cat /var/log/daemon.log::self-signed certificate.*is not trusted::YES
|
moon:: cat /var/log/daemon.log::ocsp response verification failed, no signer::YES
|
||||||
moon:: cat /var/log/daemon.log::ocsp response verification failed::YES
|
|
||||||
moon:: cat /var/log/daemon.log::certificate status is not available::YES
|
moon:: cat /var/log/daemon.log::certificate status is not available::YES
|
||||||
moon:: cat /var/log/daemon.log::constraint check failed: RULE_CRL_VALIDATION is FAILED, but requires at least GOOD::YES
|
moon:: cat /var/log/daemon.log::constraint check failed: RULE_CRL_VALIDATION is FAILED, but requires at least GOOD::YES
|
||||||
moon:: ipsec status 2> /dev/null::rw.*ESTABLISHED::NO
|
moon:: ipsec status 2> /dev/null::rw.*ESTABLISHED::NO
|
||||||
|
|||||||
Reference in New Issue
Block a user