aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/charon/credentials/credential_manager.c240
-rw-r--r--src/charon/credentials/sets/cert_cache.c11
2 files changed, 124 insertions, 127 deletions
diff --git a/src/charon/credentials/credential_manager.c b/src/charon/credentials/credential_manager.c
index 3583771fd..805bdbdf9 100644
--- a/src/charon/credentials/credential_manager.c
+++ b/src/charon/credentials/credential_manager.c
@@ -356,8 +356,8 @@ static certificate_t *fetch_ocsp(private_credential_manager_t *this, char *url,
/**
* check the signature of an OCSP response
*/
-static bool check_ocsp_response(private_credential_manager_t *this,
- ocsp_response_t *response)
+static bool verify_ocsp(private_credential_manager_t *this,
+ ocsp_response_t *response)
{
certificate_t *issuer, *subject;
identification_t *responder;
@@ -403,7 +403,7 @@ static certificate_t *get_better_ocsp(private_credential_manager_t *this,
response = (ocsp_response_t*)cand;
/* check ocsp signature */
- if (!check_ocsp_response(this, response))
+ if (!verify_ocsp(this, response))
{
DBG1(DBG_CFG, "OCSP response verification failed");
cand->destroy(cand);
@@ -418,6 +418,7 @@ static certificate_t *get_better_ocsp(private_credential_manager_t *this,
DBG1(DBG_CFG, "certificate was revoked on %T, reason: %N",
&revocation, crl_reason_names, reason);
DESTROY_IF(best);
+ *valid = VALIDATION_REVOKED;
return cand;
case VALIDATION_GOOD:
/* results in either good or stale */
@@ -476,7 +477,7 @@ static cert_validation_t check_ocsp(private_credential_manager_t *this,
best = get_better_ocsp(this, current, best, subject, issuer, &valid);
if (best && valid != VALIDATION_STALE)
{
- DBG1(DBG_CFG, " used cached ocsp response");
+ DBG1(DBG_CFG, "found cached ocsp response");
break;
}
}
@@ -547,9 +548,7 @@ static cert_validation_t check_ocsp(private_credential_manager_t *this,
*/
static certificate_t* fetch_crl(private_credential_manager_t *this, char *url)
{
- certificate_t *crl, *issuer;
- enumerator_t *enumerator;
- bool verified = FALSE;
+ certificate_t *crl;
chunk_t chunk;
/* TODO: unlock the manager while fetching? */
@@ -566,8 +565,18 @@ static certificate_t* fetch_crl(private_credential_manager_t *this, char *url)
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;
- /* verify the signature of the fetched crl */
enumerator = create_trusted_enumerator(this, KEY_ANY, crl->get_issuer(crl),
FALSE, FALSE);
while (enumerator->enumerate(enumerator, &issuer, NULL))
@@ -581,14 +590,70 @@ static certificate_t* fetch_crl(private_credential_manager_t *this, char *url)
}
}
enumerator->destroy(enumerator);
+
+ return verified;
+}
- if (!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)
+{
+ 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 is untrusted: issuer certificate not found");
- crl->destroy(crl);
- return NULL;
+ DBG1(DBG_CFG, "crl response verification failed");
+ cand->destroy(cand);
+ return best;
}
- return crl;
+
+ 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, 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 || cand->is_newer(cand, 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);
+ *valid = VALIDATION_GOOD;
+ }
+ else
+ {
+ DBG1(DBG_CFG, " crl is stale: since %#T", &valid_until);
+ *valid = VALIDATION_STALE;
+ }
+ }
+ else
+ {
+ *valid = VALIDATION_STALE;
+ cand->destroy(cand);
+ }
+ return best;
}
/**
@@ -598,16 +663,17 @@ static cert_validation_t check_crl(private_credential_manager_t *this,
x509_t *subject, x509_t *issuer,
auth_info_t *auth)
{
+ cert_validation_t valid = VALIDATION_SKIPPED;
identification_t *keyid = NULL;
- certificate_t *best_cert = NULL;
- certificate_t *cert;
+ certificate_t *best = NULL;
+ certificate_t *current;
public_key_t *public;
- cert_validation_t valid = VALIDATION_SKIPPED;
- bool stale = TRUE;
+ enumerator_t *enumerator;
+ char *uri;
/* derive the authorityKeyIdentifier from the issuer's public key */
- cert = &issuer->interface;
- public = cert->get_public_key(cert);
+ current = &issuer->interface;
+ public = current->get_public_key(current);
if (public)
{
keyid = public->get_id(public, ID_PUBKEY_SHA1);
@@ -616,146 +682,66 @@ static cert_validation_t check_crl(private_credential_manager_t *this,
/* find a cached crl by authorityKeyIdentifier */
if (keyid)
{
- enumerator_t *enumerator = create_cert_enumerator(this, CERT_X509_CRL,
- KEY_ANY, keyid, TRUE);
- certificate_t *cert;
-
- while (enumerator->enumerate(enumerator, &cert))
+ enumerator = create_cert_enumerator(this, CERT_X509_CRL, KEY_ANY,
+ keyid, FALSE);
+ while (enumerator->enumerate(enumerator, &current))
{
- /* select most recent crl */
- if (best_cert == NULL || cert->is_newer(cert, best_cert))
+ current->get_ref(current);
+ best = get_better_crl(this, current, best, subject, issuer, &valid);
+ if (best && valid != VALIDATION_STALE)
{
- DESTROY_IF(best_cert);
- best_cert = cert->get_ref(cert);
+ DBG1(DBG_CFG, "found cached crl");
+ break;
}
}
enumerator->destroy(enumerator);
}
- /* check the validity of the cached crl if one was found */
- if (best_cert)
- {
- time_t nextUpdate;
-
- stale = !best_cert->get_validity(best_cert, NULL, NULL, &nextUpdate);
- DBG1(DBG_CFG, "cached crl is %s %#T",
- stale? "stale: since":"valid: until",
- &nextUpdate, FALSE );
- }
-
- /* fallback to fetching crls from cdps defined in ca info sections */
- if (stale && keyid)
+ /* fallback to fetching crls from credential sets cdps */
+ if (keyid && valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
{
- enumerator_t *enumerator = create_cdp_enumerator(this, CERT_X509_CRL,
- keyid);
- char *uri;
+ enumerator = create_cdp_enumerator(this, CERT_X509_CRL, keyid);
while (enumerator->enumerate(enumerator, &uri))
{
- certificate_t *cert = fetch_crl(this, uri);
-
- /* redefine default since we have at least one uri */
- valid = VALIDATION_FAILED;
-
- if (cert)
+ current = fetch_crl(this, uri);
+ best = get_better_crl(this, current, best, subject, issuer, &valid);
+ if (best && valid != VALIDATION_STALE)
{
- /* select most recent crl until valid one is found */
- if (best_cert == NULL || cert->is_newer(cert, best_cert))
- {
- time_t nextUpdate;
-
- DESTROY_IF(best_cert);
- best_cert = cert;
- stale = !best_cert->get_validity(best_cert, NULL, NULL, &nextUpdate);
- DBG1(DBG_CFG, "fetched crl is %s %#T",
- stale? "stale: since":"valid: until",
- &nextUpdate, FALSE );
- if (!stale)
- {
- break;
- }
- }
- else
- {
- cert->destroy(cert);
- }
+ break;
}
}
enumerator->destroy(enumerator);
}
+ DESTROY_IF(public);
- /* fallback to fetching crls from cdps defined in the subject's certificate */
- if (stale)
+ /* fallback to fetching crls from cdps from subject's certificate */
+ if (valid != VALIDATION_GOOD && valid != VALIDATION_REVOKED)
{
- enumerator_t *enumerator = subject->create_crl_uri_enumerator(subject);
- char *uri;
+ enumerator = subject->create_crl_uri_enumerator(subject);
while (enumerator->enumerate(enumerator, &uri))
{
- certificate_t *cert = fetch_crl(this, uri);
-
- /* redefine default since we have at least one uri */
- valid = VALIDATION_FAILED;
-
- if (cert)
+ current = fetch_crl(this, uri);
+ best = get_better_crl(this, current, best, subject, issuer, &valid);
+ if (best && valid != VALIDATION_STALE)
{
- /* select most recent crl until valid one is found */
- if (best_cert == NULL || cert->is_newer(cert, best_cert))
- {
- time_t nextUpdate;
-
- DESTROY_IF(best_cert);
- best_cert = cert;
- stale = !best_cert->get_validity(best_cert, NULL, NULL, &nextUpdate);
- DBG1(DBG_CFG, "fetched crl is %s %#T",
- stale? "stale: since":"valid: until",
- &nextUpdate, FALSE );
- if (!stale)
- {
- break;
- }
- }
- else
- {
- cert->destroy(cert);
- }
+ break;
}
}
enumerator->destroy(enumerator);
}
- DESTROY_IF(public);
-
- /* if we have a crl, check the revocation status */
- if (best_cert)
+
+ /* an uri was found, but no result. switch validation state to failed */
+ if (valid == VALIDATION_SKIPPED && uri)
{
- chunk_t subject_serial = subject->get_serial(subject);
- chunk_t serial;
- time_t revocation;
- crl_reason_t reason;
- crl_t *crl = (crl_t*)best_cert;
- enumerator_t *enumerator = crl->create_enumerator(crl);
-
- /* redefine default */
- valid = stale ? VALIDATION_STALE : VALIDATION_GOOD;
-
- while (enumerator->enumerate(enumerator, &serial, &revocation, &reason))
- {
- if (chunk_equals(serial, subject_serial))
- {
- DBG1(DBG_CFG, "certificate was revoked on %T, reason: %N",
- &revocation, crl_reason_names, reason);
- valid = VALIDATION_REVOKED;
- break;
- }
- }
- enumerator->destroy(enumerator);
- best_cert->destroy(best_cert);
+ valid = VALIDATION_FAILED;
}
-
if (auth)
{
auth->add_item(auth, AUTHZ_CRL_VALIDATION, &valid);
}
+ DESTROY_IF(best);
return valid;
}
diff --git a/src/charon/credentials/sets/cert_cache.c b/src/charon/credentials/sets/cert_cache.c
index 5c112c084..a300387bf 100644
--- a/src/charon/credentials/sets/cert_cache.c
+++ b/src/charon/credentials/sets/cert_cache.c
@@ -132,6 +132,17 @@ static bool certs_filter(cert_data_t *data, relation_t **in, certificate_t **out
certificate_t *cert;
cert = (*in)->subject;
+ if (data->key == KEY_ANY && data->id &&
+ (data->cert == CERT_ANY || data->cert == CERT_X509_CRL) &&
+ cert->get_type(cert) == CERT_X509_CRL)
+ { /* CRL lookup is done using issuer/authkeyidentifier */
+ if (cert->has_issuer(cert, data->id))
+ {
+ *out = cert;
+ return TRUE;
+ }
+ }
+
if ((data->cert == CERT_ANY || cert->get_type(cert) == data->cert) &&
(!data->id || cert->has_subject(cert, data->id)))
{