revocation: Restrict OCSP signing to specific certificates
authorMartin Willi <martin@revosec.ch>
Tue, 25 Mar 2014 13:34:58 +0000 (14:34 +0100)
committerMartin Willi <martin@revosec.ch>
Mon, 31 Mar 2014 12:40:33 +0000 (14:40 +0200)
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.

src/libstrongswan/plugins/revocation/revocation_validator.c
testing/tests/ikev2/ocsp-no-signer-cert/evaltest.dat
testing/tests/ikev2/ocsp-untrusted-cert/evaltest.dat

index 284bd1f..eb9065f 100644 (file)
@@ -93,35 +93,92 @@ static certificate_t *fetch_ocsp(char *url, certificate_t *subject,
 /**
  * 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;
        identification_t *responder;
        ocsp_response_wrapper_t *wrapper;
        enumerator_t *enumerator;
-       bool verified = FALSE;
+       x509_t *x509;
+       bool verified = FALSE, found = FALSE;
 
        wrapper = ocsp_response_wrapper_create((ocsp_response_t*)response);
        lib->credmgr->add_local_set(lib->credmgr, &wrapper->set, FALSE);
 
        subject = &response->certificate;
        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);
-       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))
                {
                        DBG1(DBG_CFG, "  ocsp response correctly signed by \"%Y\"",
-                                                        issuer->get_subject(issuer));
+                                issuer->get_subject(issuer));
                        verified = TRUE;
                        break;
                }
+               DBG1(DBG_CFG, "ocsp response verification failed, "
+                        "invalid signature");
        }
        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);
        wrapper->destroy(wrapper);
+
+       if (!found)
+       {
+               DBG1(DBG_CFG, "ocsp response verification failed, "
+                        "no signer certificate '%Y' found", responder);
+       }
        return verified;
 }
 
@@ -140,9 +197,8 @@ static certificate_t *get_better_ocsp(certificate_t *cand, certificate_t *best,
        response = (ocsp_response_t*)cand;
 
        /* check ocsp signature */
-       if (!verify_ocsp(response))
+       if (!verify_ocsp(response, &issuer->interface))
        {
-               DBG1(DBG_CFG, "ocsp response verification failed");
                cand->destroy(cand);
                return best;
        }
index a2ce5ad..a6ae74f 100644 (file)
@@ -1,5 +1,5 @@
 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::constraint check failed: RULE_CRL_VALIDATION is FAILED, but requires at least GOOD::YES
 moon:: ipsec status 2> /dev/null::rw.*ESTABLISHED::NO
index 6ba1be6..1eb84ca 100644 (file)
@@ -1,6 +1,5 @@
 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::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::constraint check failed: RULE_CRL_VALIDATION is FAILED, but requires at least GOOD::YES
 moon:: ipsec status 2> /dev/null::rw.*ESTABLISHED::NO