diff options
Diffstat (limited to 'src/libstrongswan/plugins/revocation')
-rw-r--r-- | src/libstrongswan/plugins/revocation/revocation_validator.c | 134 |
1 files changed, 96 insertions, 38 deletions
diff --git a/src/libstrongswan/plugins/revocation/revocation_validator.c b/src/libstrongswan/plugins/revocation/revocation_validator.c index 1b68320df..f8e78ac0c 100644 --- a/src/libstrongswan/plugins/revocation/revocation_validator.c +++ b/src/libstrongswan/plugins/revocation/revocation_validator.c @@ -1,8 +1,9 @@ /* + * Copyright (C) 2015-2018 Tobias Brunner * Copyright (C) 2010 Martin Willi * Copyright (C) 2010 revosec AG * Copyright (C) 2009 Andreas Steffen - * Hochschule fuer Technik Rapperswil + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -15,6 +16,8 @@ * for more details. */ +#include <time.h> + #include "revocation_validator.h" #include <utils/debug.h> @@ -56,7 +59,7 @@ static certificate_t *fetch_ocsp(char *url, certificate_t *subject, certificate_t *issuer) { certificate_t *request, *response; - chunk_t send, receive; + chunk_t send, receive = chunk_empty; /* TODO: requestor name, signature */ request = lib->creds->create(lib->creds, @@ -84,6 +87,7 @@ static certificate_t *fetch_ocsp(char *url, certificate_t *subject, FETCH_END) != SUCCESS) { DBG1(DBG_CFG, "ocsp request to %s failed", url); + chunk_free(&receive); chunk_free(&send); return NULL; } @@ -351,13 +355,10 @@ static cert_validation_t check_ocsp(x509_t *subject, x509_t *issuer, { 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); - } + 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; @@ -369,12 +370,13 @@ static cert_validation_t check_ocsp(x509_t *subject, x509_t *issuer, static certificate_t* fetch_crl(char *url) { certificate_t *crl; - chunk_t chunk; + chunk_t chunk = chunk_empty; 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"); + chunk_free(&chunk); return NULL; } crl = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL, @@ -417,11 +419,11 @@ static bool verify_crl(certificate_t *crl) /** * Report the given CRL's validity and cache it if valid and requested */ -static bool is_crl_valid(certificate_t *crl, bool cache) +static bool is_crl_valid(certificate_t *crl, time_t now, bool cache) { time_t valid_until; - if (crl->get_validity(crl, NULL, NULL, &valid_until)) + if (crl->get_validity(crl, &now, NULL, &valid_until)) { DBG1(DBG_CFG, " crl is valid: until %T", &valid_until, FALSE); if (cache) @@ -435,6 +437,25 @@ static bool is_crl_valid(certificate_t *crl, bool cache) } /** + * Check if the CRL should be used yet + */ +static bool is_crl_not_valid_yet(certificate_t *crl, time_t now) +{ + time_t this_update; + + if (!crl->get_validity(crl, &now, &this_update, NULL)) + { + if (this_update > now) + { + DBG1(DBG_CFG, " crl is not valid: until %T", &this_update, FALSE); + return TRUE; + } + /* we accept stale CRLs */ + } + return FALSE; +} + +/** * Get the better of two CRLs, and check for usable CRL info */ static certificate_t *get_better_crl(certificate_t *cand, certificate_t *best, @@ -442,7 +463,7 @@ static certificate_t *get_better_crl(certificate_t *cand, certificate_t *best, bool cache, crl_t *base) { enumerator_t *enumerator; - time_t revocation; + time_t now, revocation; crl_reason_t reason; chunk_t subject_serial, serial; crl_t *crl = (crl_t*)cand; @@ -472,6 +493,12 @@ static certificate_t *get_better_crl(certificate_t *cand, certificate_t *best, cand->destroy(cand); return best; } + now = time(NULL); + if (is_crl_not_valid_yet(cand, now)) + { + cand->destroy(cand); + return best; + } subject_serial = chunk_skip_zero(subject->get_serial(subject)); enumerator = crl->create_enumerator(crl); @@ -488,7 +515,7 @@ static certificate_t *get_better_crl(certificate_t *cand, certificate_t *best, /* if the cert is on hold, a newer CRL might not contain it */ *valid = VALIDATION_ON_HOLD; } - is_crl_valid(cand, cache); + is_crl_valid(cand, now, cache); DBG1(DBG_CFG, "certificate was revoked on %T, reason: %N", &revocation, TRUE, crl_reason_names, reason); enumerator->destroy(enumerator); @@ -503,7 +530,7 @@ static certificate_t *get_better_crl(certificate_t *cand, certificate_t *best, { DESTROY_IF(best); best = cand; - if (is_crl_valid(best, cache)) + if (is_crl_valid(best, now, cache)) { *valid = VALIDATION_GOOD; } @@ -579,13 +606,38 @@ static cert_validation_t find_crl(x509_t *subject, identification_t *issuer, } /** + * Check if the issuer of the given CRL matches + */ +static bool check_issuer(certificate_t *crl, x509_t *issuer, x509_cdp_t *cdp) +{ + certificate_t *cissuer = (certificate_t*)issuer; + identification_t *id; + chunk_t chunk; + bool matches = FALSE; + + if (cdp->issuer) + { + return crl->has_issuer(crl, cdp->issuer); + } + /* check SKI/AKI first, but fall back to DN matching */ + chunk = issuer->get_subjectKeyIdentifier(issuer); + if (chunk.len) + { + id = identification_create_from_encoding(ID_KEY_ID, chunk); + matches = crl->has_issuer(crl, id); + id->destroy(id); + } + return matches || crl->has_issuer(crl, cissuer->get_subject(cissuer)); +} + +/** * Look for a delta CRL for a given base CRL */ static cert_validation_t check_delta_crl(x509_t *subject, x509_t *issuer, crl_t *base, cert_validation_t base_valid) { cert_validation_t valid = VALIDATION_SKIPPED; - certificate_t *best = NULL, *current; + certificate_t *best = NULL, *current, *cissuer = (certificate_t*)issuer; enumerator_t *enumerator; identification_t *id; x509_cdp_t *cdp; @@ -621,11 +673,12 @@ static cert_validation_t check_delta_crl(x509_t *subject, x509_t *issuer, current = fetch_crl(cdp->uri); if (current) { - if (cdp->issuer && !current->has_issuer(current, cdp->issuer)) + if (!check_issuer(current, issuer, cdp)) { DBG1(DBG_CFG, "issuer of fetched delta CRL '%Y' does not match " - "certificates CRL issuer '%Y'", - current->get_issuer(current), cdp->issuer); + "certificate's %sissuer '%Y'", + current->get_issuer(current), cdp->issuer ? "CRL " : "", + cdp->issuer ?: cissuer->get_subject(cissuer)); current->destroy(current); continue; } @@ -653,7 +706,7 @@ static cert_validation_t check_crl(x509_t *subject, x509_t *issuer, auth_cfg_t *auth) { cert_validation_t valid = VALIDATION_SKIPPED; - certificate_t *best = NULL; + certificate_t *best = NULL, *cissuer = (certificate_t*)issuer; identification_t *id; x509_cdp_t *cdp; bool uri_found = FALSE; @@ -692,11 +745,12 @@ static cert_validation_t check_crl(x509_t *subject, x509_t *issuer, current = fetch_crl(cdp->uri); if (current) { - if (cdp->issuer && !current->has_issuer(current, cdp->issuer)) + if (!check_issuer(current, issuer, cdp)) { DBG1(DBG_CFG, "issuer of fetched CRL '%Y' does not match " - "certificates CRL issuer '%Y'", - current->get_issuer(current), cdp->issuer); + "certificate's %sissuer '%Y'", + current->get_issuer(current), cdp->issuer ? "CRL " : "", + cdp->issuer ?: cissuer->get_subject(cissuer)); current->destroy(current); continue; } @@ -722,18 +776,15 @@ static cert_validation_t check_crl(x509_t *subject, x509_t *issuer, { 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 { - 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); - } + auth->add(auth, AUTH_RULE_CRL_VALIDATION, valid); } DESTROY_IF(best); return valid; @@ -753,8 +804,7 @@ METHOD(cert_validator_t, validate, bool, if (this->enable_ocsp) { - switch (check_ocsp((x509_t*)subject, (x509_t*)issuer, - pathlen ? NULL : auth)) + switch (check_ocsp((x509_t*)subject, (x509_t*)issuer, auth)) { case VALIDATION_GOOD: DBG1(DBG_CFG, "certificate status is good"); @@ -776,11 +826,14 @@ METHOD(cert_validator_t, validate, bool, break; } } + else + { + auth->add(auth, AUTH_RULE_OCSP_VALIDATION, VALIDATION_SKIPPED); + } if (this->enable_crl) { - switch (check_crl((x509_t*)subject, (x509_t*)issuer, - pathlen ? NULL : auth)) + switch (check_crl((x509_t*)subject, (x509_t*)issuer, auth)) { case VALIDATION_GOOD: DBG1(DBG_CFG, "certificate status is good"); @@ -800,6 +853,11 @@ METHOD(cert_validator_t, validate, bool, break; } } + else + { + auth->add(auth, AUTH_RULE_CRL_VALIDATION, + auth->get(auth, AUTH_RULE_OCSP_VALIDATION)); + } lib->credmgr->call_hook(lib->credmgr, CRED_HOOK_VALIDATION_FAILED, subject); |