Moved CRL/OCSP checking to a dedicated plugin called revocation
[strongswan.git] / src / libstrongswan / credentials / credential_manager.c
index 8df232b..3b671c7 100644 (file)
 #include <threading/thread_value.h>
 #include <threading/mutex.h>
 #include <threading/rwlock.h>
-#include <selectors/traffic_selector.h>
 #include <utils/linked_list.h>
 #include <credentials/sets/cert_cache.h>
 #include <credentials/sets/auth_cfg_wrapper.h>
-#include <credentials/sets/ocsp_response_wrapper.h>
 #include <credentials/certificates/x509.h>
-#include <credentials/certificates/crl.h>
-#include <credentials/certificates/ocsp_request.h>
-#include <credentials/certificates/ocsp_response.h>
 
 /**
  * Maximum length of a certificate trust chain
@@ -452,492 +447,6 @@ static void cache_queue(private_credential_manager_t *this)
 }
 
 /**
- * forward declaration
- */
-static enumerator_t *create_trusted_enumerator(private_credential_manager_t *this,
-                                       key_type_t type, identification_t *id, bool online);
-
-/**
- * Do an OCSP request
- */
-static certificate_t *fetch_ocsp(private_credential_manager_t *this, char *url,
-                                                                certificate_t *subject, certificate_t *issuer)
-{
-       certificate_t *request, *response;
-       chunk_t send, receive;
-
-       /* TODO: requestor name, signature */
-       request = lib->creds->create(lib->creds,
-                                               CRED_CERTIFICATE, CERT_X509_OCSP_REQUEST,
-                                               BUILD_CA_CERT, issuer,
-                                               BUILD_CERT, subject, BUILD_END);
-       if (!request)
-       {
-               DBG1(DBG_CFG, "generating ocsp request failed");
-               return NULL;
-       }
-
-       send = request->get_encoding(request);
-       request->destroy(request);
-
-       DBG1(DBG_CFG, "  requesting ocsp status from '%s' ...", url);
-       if (lib->fetcher->fetch(lib->fetcher, url, &receive,
-                                                       FETCH_REQUEST_DATA, send,
-                                                       FETCH_REQUEST_TYPE, "application/ocsp-request",
-                                                       FETCH_END) != SUCCESS)
-       {
-               DBG1(DBG_CFG, "ocsp request to %s failed", url);
-               chunk_free(&send);
-               return NULL;
-       }
-       chunk_free(&send);
-
-       response = lib->creds->create(lib->creds,
-                                                                 CRED_CERTIFICATE, CERT_X509_OCSP_RESPONSE,
-                                                                 BUILD_BLOB_ASN1_DER, receive, BUILD_END);
-       chunk_free(&receive);
-       if (!response)
-       {
-               DBG1(DBG_CFG, "parsing ocsp response failed");
-               return NULL;
-       }
-       return response;
-}
-
-/**
- * check the signature of an OCSP response
- */
-static bool verify_ocsp(private_credential_manager_t *this,
-                                               ocsp_response_t *response)
-{
-       certificate_t *issuer, *subject;
-       identification_t *responder;
-       ocsp_response_wrapper_t *wrapper;
-       enumerator_t *enumerator;
-       bool verified = FALSE;
-
-       wrapper = ocsp_response_wrapper_create((ocsp_response_t*)response);
-       add_local_set(this, &wrapper->set);
-
-       subject = &response->certificate;
-       responder = subject->get_issuer(subject);
-       enumerator = create_trusted_enumerator(this, KEY_ANY, responder, FALSE);
-       while (enumerator->enumerate(enumerator, &issuer, NULL))
-       {
-               if (this->cache->issued_by(this->cache, subject, issuer))
-               {
-                       DBG1(DBG_CFG, "  ocsp response correctly signed by \"%Y\"",
-                                                        issuer->get_subject(issuer));
-                       verified = TRUE;
-                       break;
-               }
-       }
-       enumerator->destroy(enumerator);
-
-       remove_local_set(this, &wrapper->set);
-       wrapper->destroy(wrapper);
-       return verified;
-}
-
-/**
- * Get the better of two OCSP responses, and check for usable OCSP info
- */
-static certificate_t *get_better_ocsp(private_credential_manager_t *this,
-                                                                         certificate_t *cand, certificate_t *best,
-                                                                         x509_t *subject, x509_t *issuer,
-                                                                         cert_validation_t *valid, bool cache)
-{
-       ocsp_response_t *response;
-       time_t revocation, this_update, next_update, valid_until;
-       crl_reason_t reason;
-       bool revoked = FALSE;
-
-       response = (ocsp_response_t*)cand;
-
-       /* check ocsp signature */
-       if (!verify_ocsp(this, response))
-       {
-               DBG1(DBG_CFG, "ocsp response verification failed");
-               cand->destroy(cand);
-               return best;
-       }
-       /* check if response contains our certificate */
-       switch (response->get_status(response, subject, issuer, &revocation, &reason,
-                                                                &this_update, &next_update))
-       {
-               case VALIDATION_REVOKED:
-                       /* subject has been revoked by a valid OCSP response */
-                       DBG1(DBG_CFG, "certificate was revoked on %T, reason: %N",
-                                                 &revocation, TRUE, crl_reason_names, reason);
-                       revoked = TRUE;
-                       break;
-               case VALIDATION_GOOD:
-                       /* results in either good or stale */
-                       break;
-               default:
-               case VALIDATION_FAILED:
-                       /* candidate unusable, does not contain our cert */
-                       DBG1(DBG_CFG, "  ocsp response contains no status on our certificate");
-                       cand->destroy(cand);
-                       return best;
-       }
-
-       /* select the better of the two responses */
-       if (best == NULL || certificate_is_newer(cand, best))
-       {
-               DESTROY_IF(best);
-               best = cand;
-               if (best->get_validity(best, NULL, NULL, &valid_until))
-               {
-                       DBG1(DBG_CFG, "  ocsp response is valid: until %T",
-                                                        &valid_until, FALSE);
-                       *valid = VALIDATION_GOOD;
-                       if (cache)
-                       {       /* cache non-stale only, stale certs get refetched */
-                               cache_cert(this, best);
-                       }
-               }
-               else
-               {
-                       DBG1(DBG_CFG, "  ocsp response is stale: since %T",
-                                                        &valid_until, FALSE);
-                       *valid = VALIDATION_STALE;
-               }
-       }
-       else
-       {
-               *valid = VALIDATION_STALE;
-               cand->destroy(cand);
-       }
-       if (revoked)
-       {       /* revoked always counts, even if stale */
-               *valid = VALIDATION_REVOKED;
-       }
-       return best;
-}
-
-/**
- * validate a x509 certificate using OCSP
- */
-static cert_validation_t check_ocsp(private_credential_manager_t *this,
-                                                                       x509_t *subject, x509_t *issuer,
-                                                                       auth_cfg_t *auth)
-{
-       enumerator_t *enumerator;
-       cert_validation_t valid = VALIDATION_SKIPPED;
-       certificate_t *best = NULL, *current;
-       identification_t *keyid = NULL;
-       public_key_t *public;
-       chunk_t chunk;
-       char *uri = NULL;
-
-       /** lookup cache for valid OCSP responses */
-       enumerator = create_cert_enumerator(this, CERT_X509_OCSP_RESPONSE,
-                                                                               KEY_ANY, NULL, FALSE);
-       while (enumerator->enumerate(enumerator, &current))
-       {
-               current->get_ref(current);
-               best = get_better_ocsp(this, current, best, subject, issuer,
-                                                          &valid, FALSE);
-               if (best && valid != VALIDATION_STALE)
-               {
-                       DBG1(DBG_CFG, "  using cached ocsp response");
-                       break;
-               }
-       }
-       enumerator->destroy(enumerator);
-
-       /* derive the authorityKeyIdentifier from the issuer's public key */
-       current = &issuer->interface;
-       public = current->get_public_key(current);
-       if (public && public->get_fingerprint(public, KEY_ID_PUBKEY_SHA1, &chunk))
-       {
-               keyid = identification_create_from_encoding(ID_KEY_ID, chunk);
-       }
-       /** fetch from configured OCSP responder URLs */
-       if (keyid && valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
-       {
-               enumerator = create_cdp_enumerator(this, CERT_X509_OCSP_RESPONSE, keyid);
-               while (enumerator->enumerate(enumerator, &uri))
-               {
-                       current = fetch_ocsp(this, uri, &subject->interface,
-                                                                &issuer->interface);
-                       if (current)
-                       {
-                               best = get_better_ocsp(this, current, best, subject, issuer,
-                                                                          &valid, TRUE);
-                               if (best && valid != VALIDATION_STALE)
-                               {
-                                       break;
-                               }
-                       }
-               }
-               enumerator->destroy(enumerator);
-       }
-       DESTROY_IF(public);
-       DESTROY_IF(keyid);
-
-       /* fallback to URL fetching from subject certificate's URIs */
-       if (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
-       {
-               enumerator = subject->create_ocsp_uri_enumerator(subject);
-               while (enumerator->enumerate(enumerator, &uri))
-               {
-                       current = fetch_ocsp(this, uri, &subject->interface,
-                                                                &issuer->interface);
-                       if (current)
-                       {
-                               best = get_better_ocsp(this, current, best, subject, issuer,
-                                                                          &valid, TRUE);
-                               if (best && valid != VALIDATION_STALE)
-                               {
-                                       break;
-                               }
-                       }
-               }
-               enumerator->destroy(enumerator);
-       }
-       /* an uri was found, but no result. switch validation state to failed */
-       if (valid == VALIDATION_SKIPPED && uri)
-       {
-               valid = VALIDATION_FAILED;
-       }
-       if (auth)
-       {
-               auth->add(auth, AUTH_RULE_OCSP_VALIDATION, valid);
-               if (valid == VALIDATION_GOOD)
-               {       /* successful OCSP check fulfills also CRL constraint */
-                       auth->add(auth, AUTH_RULE_CRL_VALIDATION, VALIDATION_GOOD);
-               }
-       }
-       DESTROY_IF(best);
-       return valid;
-}
-
-/**
- * fetch a CRL from an URL
- */
-static certificate_t* fetch_crl(private_credential_manager_t *this, char *url)
-{
-       certificate_t *crl;
-       chunk_t chunk;
-
-       DBG1(DBG_CFG, "  fetching crl from '%s' ...", url);
-       if (lib->fetcher->fetch(lib->fetcher, url, &chunk, FETCH_END) != SUCCESS)
-       {
-               DBG1(DBG_CFG, "crl fetching failed");
-               return NULL;
-       }
-       crl = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL,
-                                                        BUILD_BLOB_ASN1_DER, chunk, BUILD_END);
-       chunk_free(&chunk);
-       if (!crl)
-       {
-               DBG1(DBG_CFG, "crl fetched successfully but parsing failed");
-               return NULL;
-       }
-       return crl;
-}
-
-/**
- * check the signature of an CRL
- */
-static bool verify_crl(private_credential_manager_t *this, certificate_t *crl)
-{
-       certificate_t *issuer;
-       enumerator_t *enumerator;
-       bool verified = FALSE;
-
-       enumerator = create_trusted_enumerator(this, KEY_ANY, crl->get_issuer(crl),
-                                                                                  FALSE);
-       while (enumerator->enumerate(enumerator, &issuer, NULL))
-       {
-               if (this->cache->issued_by(this->cache, crl, issuer))
-               {
-                       DBG1(DBG_CFG, "  crl correctly signed by \"%Y\"",
-                                                  issuer->get_subject(issuer));
-                       verified = TRUE;
-                       break;
-               }
-       }
-       enumerator->destroy(enumerator);
-
-       return verified;
-}
-
-/**
- * Get the better of two CRLs, and check for usable CRL info
- */
-static certificate_t *get_better_crl(private_credential_manager_t *this,
-                                                                        certificate_t *cand, certificate_t *best,
-                                                                        x509_t *subject, x509_t *issuer,
-                                                                        cert_validation_t *valid, bool cache)
-{
-       enumerator_t *enumerator;
-       time_t revocation, valid_until;
-       crl_reason_t reason;
-       chunk_t serial;
-       crl_t *crl;
-
-       /* check CRL signature */
-       if (!verify_crl(this, cand))
-       {
-               DBG1(DBG_CFG, "crl response verification failed");
-               cand->destroy(cand);
-               return best;
-       }
-
-       crl = (crl_t*)cand;
-       enumerator = crl->create_enumerator(crl);
-       while (enumerator->enumerate(enumerator, &serial, &revocation, &reason))
-       {
-               if (chunk_equals(serial, subject->get_serial(subject)))
-               {
-                       DBG1(DBG_CFG, "certificate was revoked on %T, reason: %N",
-                                &revocation, TRUE, crl_reason_names, reason);
-                       *valid = VALIDATION_REVOKED;
-                       enumerator->destroy(enumerator);
-                       DESTROY_IF(best);
-                       return cand;
-               }
-       }
-       enumerator->destroy(enumerator);
-
-       /* select the better of the two CRLs */
-       if (best == NULL || crl_is_newer(crl, (crl_t*)best))
-       {
-               DESTROY_IF(best);
-               best = cand;
-               if (best->get_validity(best, NULL, NULL, &valid_until))
-               {
-                       DBG1(DBG_CFG, "  crl is valid: until %T", &valid_until, FALSE);
-                       *valid = VALIDATION_GOOD;
-                       if (cache)
-                       {       /* we cache non-stale crls only, as a stale crls are refetched */
-                               cache_cert(this, best);
-                       }
-               }
-               else
-               {
-                       DBG1(DBG_CFG, "  crl is stale: since %T", &valid_until, FALSE);
-                       *valid = VALIDATION_STALE;
-               }
-       }
-       else
-       {
-               *valid = VALIDATION_STALE;
-               cand->destroy(cand);
-       }
-       return best;
-}
-
-/**
- * validate a x509 certificate using CRL
- */
-static cert_validation_t check_crl(private_credential_manager_t *this,
-                                                                  x509_t *subject, x509_t *issuer,
-                                                                  auth_cfg_t *auth)
-{
-       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;
-
-       /* derive the authorityKeyIdentifier from the issuer's public key */
-       current = &issuer->interface;
-       public = current->get_public_key(current);
-       if (public && public->get_fingerprint(public, KEY_ID_PUBKEY_SHA1, &chunk))
-       {
-               keyid = identification_create_from_encoding(ID_KEY_ID, chunk);
-
-               /* find a cached crl by authorityKeyIdentifier */
-               enumerator = create_cert_enumerator(this, CERT_X509_CRL, KEY_ANY,
-                                                                                       keyid, FALSE);
-               while (enumerator->enumerate(enumerator, &current))
-               {
-                       current->get_ref(current);
-                       best = get_better_crl(this, current, best, subject, issuer,
-                                                                 &valid, FALSE);
-                       if (best && valid != VALIDATION_STALE)
-                       {
-                               DBG1(DBG_CFG, "  using cached crl");
-                               break;
-                       }
-               }
-               enumerator->destroy(enumerator);
-
-               /* fallback to fetching crls from credential sets cdps */
-               if (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
-               {
-                       enumerator = create_cdp_enumerator(this, CERT_X509_CRL, keyid);
-
-                       while (enumerator->enumerate(enumerator, &uri))
-                       {
-                               current = fetch_crl(this, uri);
-                               if (current)
-                               {
-                                       best = get_better_crl(this, current, best, subject, issuer,
-                                                                                 &valid, TRUE);
-                                       if (best && valid != VALIDATION_STALE)
-                                       {
-                                               break;
-                                       }
-                               }
-                       }
-                       enumerator->destroy(enumerator);
-               }
-               keyid->destroy(keyid);
-       }
-       DESTROY_IF(public);
-
-       /* fallback to fetching crls from cdps from subject's certificate */
-       if (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
-       {
-               enumerator = subject->create_crl_uri_enumerator(subject);
-
-               while (enumerator->enumerate(enumerator, &uri))
-               {
-                       current = fetch_crl(this, uri);
-                       if (current)
-                       {
-                               best = get_better_crl(this, current, best, subject, issuer,
-                                                                         &valid, TRUE);
-                               if (best && valid != VALIDATION_STALE)
-                               {
-                                       break;
-                               }
-                       }
-               }
-               enumerator->destroy(enumerator);
-       }
-
-       /* an uri was found, but no result. switch validation state to failed */
-       if (valid == VALIDATION_SKIPPED && uri)
-       {
-               valid = VALIDATION_FAILED;
-       }
-       if (auth)
-       {
-               if (valid == VALIDATION_SKIPPED)
-               {       /* if we skipped CRL validation, we use the result of OCSP for
-                        * constraint checking */
-                       auth->add(auth, AUTH_RULE_CRL_VALIDATION,
-                                         auth->get(auth, AUTH_RULE_OCSP_VALIDATION));
-               }
-               else
-               {
-                       auth->add(auth, AUTH_RULE_CRL_VALIDATION, valid);
-               }
-       }
-       DESTROY_IF(best);
-       return valid;
-}
-
-/**
  * check a certificate for its lifetime
  */
 static bool check_certificate(private_credential_manager_t *this,
@@ -976,46 +485,6 @@ static bool check_certificate(private_credential_manager_t *this,
                                 pathlen, pathlen_constraint);
                        return FALSE;
                }
-
-               if (online)
-               {
-                       DBG1(DBG_CFG, "checking certificate status of \"%Y\"",
-                                                  subject->get_subject(subject));
-                       switch (check_ocsp(this, (x509_t*)subject, (x509_t*)issuer, auth))
-                       {
-                               case VALIDATION_GOOD:
-                                       DBG1(DBG_CFG, "certificate status is good");
-                                       return TRUE;
-                               case VALIDATION_REVOKED:
-                                       /* has already been logged */
-                                       return FALSE;
-                               case VALIDATION_SKIPPED:
-                                       DBG2(DBG_CFG, "ocsp check skipped, no ocsp found");
-                                       break;
-                               case VALIDATION_STALE:
-                                       DBG1(DBG_CFG, "ocsp information stale, fallback to crl");
-                                       break;
-                               case VALIDATION_FAILED:
-                                       DBG1(DBG_CFG, "ocsp check failed, fallback to crl");
-                                       break;
-                       }
-                       switch (check_crl(this, (x509_t*)subject, (x509_t*)issuer, auth))
-                       {
-                               case VALIDATION_GOOD:
-                                       DBG1(DBG_CFG, "certificate status is good");
-                                       return TRUE;
-                               case VALIDATION_REVOKED:
-                                       /* has already been logged */
-                                       return FALSE;
-                               case VALIDATION_FAILED:
-                               case VALIDATION_SKIPPED:
-                                       DBG1(DBG_CFG, "certificate status is not available");
-                                       break;
-                               case VALIDATION_STALE:
-                                       DBG1(DBG_CFG, "certificate status is unknown, crl is stale");
-                                       break;
-                       }
-               }
        }
 
        enumerator = this->validators->create_enumerator(this->validators);