diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/charon/credentials/credential_manager.c | 240 | ||||
-rw-r--r-- | src/charon/credentials/sets/cert_cache.c | 11 |
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, ¤t)) { - /* 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))) { |