Use certificate CRLIssuer information to look up cacched CRLs or CDPs
authorMartin Willi <martin@revosec.ch>
Thu, 2 Dec 2010 14:38:44 +0000 (15:38 +0100)
committerMartin Willi <martin@revosec.ch>
Wed, 5 Jan 2011 15:45:56 +0000 (16:45 +0100)
src/libstrongswan/plugins/revocation/revocation_validator.c

index 511a04a..a20f40a 100644 (file)
@@ -350,7 +350,7 @@ static bool verify_crl(certificate_t *crl)
  * Get the better of two CRLs, and check for usable CRL info
  */
 static certificate_t *get_better_crl(certificate_t *cand, certificate_t *best,
-               x509_t *subject, x509_t *issuer, cert_validation_t *valid, bool cache)
+                                               x509_t *subject, cert_validation_t *valid, bool cache)
 {
        enumerator_t *enumerator;
        time_t revocation, valid_until;
@@ -411,78 +411,116 @@ static certificate_t *get_better_crl(certificate_t *cand, certificate_t *best,
 }
 
 /**
- * validate a x509 certificate using CRL
+ * Find or fetch a certificate for a given crlIssuer
  */
-static cert_validation_t check_crl(x509_t *subject, x509_t *issuer,
-                                                                  auth_cfg_t *auth)
+static cert_validation_t find_crl(x509_t *subject, identification_t *issuer,
+                                                                 certificate_t **best, bool *uri_found)
 {
        cert_validation_t valid = VALIDATION_SKIPPED;
-       identification_t *keyid = NULL;
-       certificate_t *best = NULL;
-       certificate_t *current;
-       public_key_t *public;
        enumerator_t *enumerator;
-       chunk_t chunk;
-       char *uri = NULL;
+       certificate_t *current;
+       char *uri;
 
-       /* derive the authorityKeyIdentifier from the issuer's public key */
-       current = &issuer->interface;
-       public = current->get_public_key(current);
-       if (public && public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &chunk))
+       /* find a cached crl */
+       enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
+                                                                               CERT_X509_CRL, KEY_ANY, issuer, FALSE);
+       while (enumerator->enumerate(enumerator, &current))
        {
-               keyid = identification_create_from_encoding(ID_KEY_ID, chunk);
-
-               /* find a cached crl by authorityKeyIdentifier */
-               enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
-                                                                               CERT_X509_CRL, KEY_ANY, keyid, FALSE);
-               while (enumerator->enumerate(enumerator, &current))
+               current->get_ref(current);
+               *best = get_better_crl(current, *best, subject, &valid, FALSE);
+               if (*best && valid != VALIDATION_STALE)
                {
-                       current->get_ref(current);
-                       best = get_better_crl(current, best, subject, issuer,
-                                                                 &valid, FALSE);
-                       if (best && valid != VALIDATION_STALE)
-                       {
-                               DBG1(DBG_CFG, "  using cached crl");
-                               break;
-                       }
+                       DBG1(DBG_CFG, "  using cached crl");
+                       break;
                }
-               enumerator->destroy(enumerator);
+       }
+       enumerator->destroy(enumerator);
 
-               /* fallback to fetching crls from credential sets cdps */
-               if (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
+       /* fallback to fetching crls from credential sets cdps */
+       if (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
+       {
+               enumerator = lib->credmgr->create_cdp_enumerator(lib->credmgr,
+                                                                                                                CERT_X509_CRL, issuer);
+               while (enumerator->enumerate(enumerator, &uri))
                {
-                       enumerator = lib->credmgr->create_cdp_enumerator(lib->credmgr,
-                                                                                                               CERT_X509_CRL, keyid);
-                       while (enumerator->enumerate(enumerator, &uri))
+                       *uri_found = TRUE;
+                       current = fetch_crl(uri);
+                       if (!current->has_issuer(current, issuer))
                        {
-                               current = fetch_crl(uri);
-                               if (current)
+                               DBG1(DBG_CFG, "issuer of fetched CRL '%Y' does not match CRL "
+                                        "issuer '%Y'", current->get_issuer(current), issuer);
+                               current->destroy(current);
+                               continue;
+                       }
+                       if (current)
+                       {
+                               *best = get_better_crl(current, *best, subject, &valid, TRUE);
+                               if (*best && valid != VALIDATION_STALE)
                                {
-                                       best = get_better_crl(current, best, subject, issuer,
-                                                                                 &valid, TRUE);
-                                       if (best && valid != VALIDATION_STALE)
-                                       {
-                                               break;
-                                       }
+                                       break;
                                }
                        }
-                       enumerator->destroy(enumerator);
                }
-               keyid->destroy(keyid);
+               enumerator->destroy(enumerator);
        }
-       DESTROY_IF(public);
+       return valid;
+}
+
+/**
+ * validate a x509 certificate using CRL
+ */
+static cert_validation_t check_crl(x509_t *subject, x509_t *issuer,
+                                                                  auth_cfg_t *auth)
+{
+       cert_validation_t valid = VALIDATION_SKIPPED;
+       identification_t *id;
+       certificate_t *best = NULL;
+       bool uri_found = FALSE;
+       certificate_t *current;
+       enumerator_t *enumerator;
+       chunk_t chunk;
+       char *uri;
+
+       /* use issuers subjectKeyIdentifier to find a cached CRL / fetch from CDP */
+       chunk = issuer->get_subjectKeyIdentifier(issuer);
+       if (chunk.len)
+       {
+               id = identification_create_from_encoding(ID_KEY_ID, chunk);
+               valid = find_crl(subject, id, &best, &uri_found);
+               id->destroy(id);
+       }
+
+       /* find a cached CRL or fetch via configured CDP via CRLIssuer */
+       enumerator = subject->create_crl_uri_enumerator(subject);
+       while (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED &&
+                  enumerator->enumerate(enumerator, &uri, &id))
+       {
+               if (id)
+               {
+                       valid = find_crl(subject, id, &best, &uri_found);
+               }
+       }
+       enumerator->destroy(enumerator);
 
-       /* fallback to fetching crls from cdps from subject's certificate */
+       /* fallback to fetching CRLs from CDPs found in subjects certificate */
        if (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
        {
                enumerator = subject->create_crl_uri_enumerator(subject);
-               while (enumerator->enumerate(enumerator, &uri, NULL))
+               while (enumerator->enumerate(enumerator, &uri, &id))
                {
+                       uri_found = TRUE;
                        current = fetch_crl(uri);
                        if (current)
                        {
-                               best = get_better_crl(current, best, subject, issuer,
-                                                                         &valid, TRUE);
+                               if (id && !current->has_issuer(current, id))
+                               {
+                                       DBG1(DBG_CFG, "issuer of fetched CRL '%Y' does not match "
+                                                "certificates CRL issuer '%Y'",
+                                                current->get_issuer(current), id);
+                                       current->destroy(current);
+                                       continue;
+                               }
+                               best = get_better_crl(current, best, subject, &valid, TRUE);
                                if (best && valid != VALIDATION_STALE)
                                {
                                        break;
@@ -493,7 +531,7 @@ static cert_validation_t check_crl(x509_t *subject, x509_t *issuer,
        }
 
        /* an uri was found, but no result. switch validation state to failed */
-       if (valid == VALIDATION_SKIPPED && uri)
+       if (valid == VALIDATION_SKIPPED && uri_found)
        {
                valid = VALIDATION_FAILED;
        }