summaryrefslogtreecommitdiff
path: root/src/libstrongswan/plugins/revocation/revocation_validator.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/plugins/revocation/revocation_validator.c')
-rw-r--r--src/libstrongswan/plugins/revocation/revocation_validator.c134
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);