aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Willi <martin@revosec.ch>2013-07-09 11:55:32 +0200
committerMartin Willi <martin@revosec.ch>2013-07-18 16:00:30 +0200
commit4d7a762871f52dac5c7bd7808edc94a55dd40e1a (patch)
treea051510dbcf77c3490e3bd4c63c262c889c89073
parentf7cff7fac45e7914dd742d4348be1b17b9e63e0c (diff)
downloadstrongswan-4d7a762871f52dac5c7bd7808edc94a55dd40e1a.tar.bz2
strongswan-4d7a762871f52dac5c7bd7808edc94a55dd40e1a.tar.xz
credmgr: introduce a hook function to catch trust chain validation errors
-rw-r--r--src/libcharon/plugins/addrblock/addrblock_validator.c7
-rw-r--r--src/libcharon/plugins/coupling/coupling_validator.c4
-rw-r--r--src/libstrongswan/credentials/cert_validator.h3
-rw-r--r--src/libstrongswan/credentials/credential_manager.c45
-rw-r--r--src/libstrongswan/credentials/credential_manager.h54
-rw-r--r--src/libstrongswan/plugins/constraints/constraints_validator.c8
-rw-r--r--src/libstrongswan/plugins/revocation/revocation_validator.c6
7 files changed, 120 insertions, 7 deletions
diff --git a/src/libcharon/plugins/addrblock/addrblock_validator.c b/src/libcharon/plugins/addrblock/addrblock_validator.c
index 65f4ed08c..372c978a2 100644
--- a/src/libcharon/plugins/addrblock/addrblock_validator.c
+++ b/src/libcharon/plugins/addrblock/addrblock_validator.c
@@ -94,7 +94,12 @@ METHOD(cert_validator_t, validate, bool,
if (subject->get_type(subject) == CERT_X509 &&
issuer->get_type(issuer) == CERT_X509)
{
- return check_addrblock((x509_t*)subject, (x509_t*)issuer);
+ if (!check_addrblock((x509_t*)subject, (x509_t*)issuer))
+ {
+ lib->credmgr->call_hook(lib->credmgr, CRED_HOOK_POLICY_VIOLATION,
+ subject);
+ return FALSE;
+ }
}
return TRUE;
}
diff --git a/src/libcharon/plugins/coupling/coupling_validator.c b/src/libcharon/plugins/coupling/coupling_validator.c
index 539be7548..5a72531fa 100644
--- a/src/libcharon/plugins/coupling/coupling_validator.c
+++ b/src/libcharon/plugins/coupling/coupling_validator.c
@@ -167,6 +167,8 @@ METHOD(cert_validator_t, validate, bool,
{
DBG1(DBG_CFG, "coupling new certificate '%Y' failed",
subject->get_subject(subject));
+ lib->credmgr->call_hook(lib->credmgr
+ CRED_HOOK_POLICY_VIOLATION, subject);
}
}
else
@@ -174,6 +176,8 @@ METHOD(cert_validator_t, validate, bool,
DBG1(DBG_CFG, "coupling new certificate '%Y' failed, limit of %d "
"couplings reached", subject->get_subject(subject),
this->max_couplings);
+ lib->credmgr->call_hook(lib->credmgr, CRED_HOOK_POLICY_VIOLATION,
+ subject);
}
this->mutex->unlock(this->mutex);
}
diff --git a/src/libstrongswan/credentials/cert_validator.h b/src/libstrongswan/credentials/cert_validator.h
index 325fa0af3..6b28f35c1 100644
--- a/src/libstrongswan/credentials/cert_validator.h
+++ b/src/libstrongswan/credentials/cert_validator.h
@@ -53,6 +53,9 @@ struct cert_validator_t {
/**
* Validate a subject certificate in relation to its issuer.
*
+ * If FALSE is returned, the validator should call_hook() on the
+ * credential manager with an appropriate type and the certificate.
+ *
* @param subject subject certificate to check
* @param issuer issuer of subject
* @param online whether to do online revocation checking
diff --git a/src/libstrongswan/credentials/credential_manager.c b/src/libstrongswan/credentials/credential_manager.c
index fa255551b..de19c8d96 100644
--- a/src/libstrongswan/credentials/credential_manager.c
+++ b/src/libstrongswan/credentials/credential_manager.c
@@ -81,6 +81,16 @@ struct private_credential_manager_t {
* mutex for cache queue
*/
mutex_t *queue_mutex;
+
+ /**
+ * Registered hook to call on validation errors
+ */
+ credential_hook_t hook;
+
+ /**
+ * Registered data to pass to hook
+ */
+ void *hook_data;
};
/** data to pass to create_private_enumerator */
@@ -126,6 +136,22 @@ typedef struct {
enumerator_t *exclusive;
} sets_enumerator_t;
+METHOD(credential_manager_t, set_hook, void,
+ private_credential_manager_t *this, credential_hook_t hook, void *data)
+{
+ this->hook = hook;
+ this->hook_data = data;
+}
+
+METHOD(credential_manager_t, call_hook, void,
+ private_credential_manager_t *this, credential_hook_type_t type,
+ certificate_t *cert)
+{
+ if (this->hook)
+ {
+ this->hook(this->hook_data, type, cert);
+ }
+}
METHOD(enumerator_t, sets_enumerate, bool,
sets_enumerator_t *this, credential_set_t **set)
@@ -553,15 +579,17 @@ static bool check_lifetime(private_credential_manager_t *this,
{
DBG1(DBG_CFG, "%s certificate invalid (valid from %T to %T)",
label, &not_before, FALSE, &not_after, FALSE);
- return FALSE;
+ break;
}
return TRUE;
case SUCCESS:
return TRUE;
case FAILED:
default:
- return FALSE;
+ break;
}
+ call_hook(this, CRED_HOOK_EXPIRED, cert);
+ return FALSE;
}
/**
@@ -722,9 +750,10 @@ static bool verify_trust_chain(private_credential_manager_t *this,
{
if (current->equals(current, issuer))
{
- DBG1(DBG_CFG, " self-signed certificate \"%Y\" is not trusted",
- current->get_subject(current));
+ DBG1(DBG_CFG, " self-signed certificate \"%Y\" is not "
+ "trusted", current->get_subject(current));
issuer->destroy(issuer);
+ call_hook(this, CRED_HOOK_UNTRUSTED_ROOT, current);
break;
}
auth->add(auth, AUTH_RULE_IM_CERT, issuer->get_ref(issuer));
@@ -736,6 +765,7 @@ static bool verify_trust_chain(private_credential_manager_t *this,
{
DBG1(DBG_CFG, "no issuer certificate found for \"%Y\"",
current->get_subject(current));
+ call_hook(this, CRED_HOOK_NO_ISSUER, current);
break;
}
}
@@ -754,8 +784,8 @@ static bool verify_trust_chain(private_credential_manager_t *this,
current = issuer;
if (trusted)
{
- DBG1(DBG_CFG, " reached self-signed root ca with a path length of %d",
- pathlen);
+ DBG1(DBG_CFG, " reached self-signed root ca with a "
+ "path length of %d", pathlen);
break;
}
}
@@ -763,6 +793,7 @@ static bool verify_trust_chain(private_credential_manager_t *this,
if (pathlen > MAX_TRUST_PATH_LEN)
{
DBG1(DBG_CFG, "maximum path length of %d exceeded", MAX_TRUST_PATH_LEN);
+ call_hook(this, CRED_HOOK_EXCEEDED_PATH_LEN, subject);
}
if (trusted)
{
@@ -1305,6 +1336,8 @@ credential_manager_t *credential_manager_create()
.remove_local_set = _remove_local_set,
.add_validator = _add_validator,
.remove_validator = _remove_validator,
+ .set_hook = _set_hook,
+ .call_hook = _call_hook,
.destroy = _destroy,
},
.sets = linked_list_create(),
diff --git a/src/libstrongswan/credentials/credential_manager.h b/src/libstrongswan/credentials/credential_manager.h
index 73c585734..445ea3f9c 100644
--- a/src/libstrongswan/credentials/credential_manager.h
+++ b/src/libstrongswan/credentials/credential_manager.h
@@ -22,6 +22,7 @@
#define CREDENTIAL_MANAGER_H_
typedef struct credential_manager_t credential_manager_t;
+typedef enum credential_hook_type_t credential_hook_type_t;
#include <utils/identification.h>
#include <collections/enumerator.h>
@@ -33,6 +34,37 @@ typedef struct credential_manager_t credential_manager_t;
#include <credentials/cert_validator.h>
/**
+ * Type of a credential hook error/event.
+ */
+enum credential_hook_type_t {
+ /** The certificate has expired (or is not yet valid) */
+ CRED_HOOK_EXPIRED,
+ /** The certificate has been revoked */
+ CRED_HOOK_REVOKED,
+ /** Checking certificate revocation failed. This does not necessarily mean
+ * the certificate is rejected, just that revocation checking failed. */
+ CRED_HOOK_VALIDATION_FAILED,
+ /** No trusted issuer certificate has been found for this certificate */
+ CRED_HOOK_NO_ISSUER,
+ /** Encountered a self-signed (root) certificate, but it is not trusted */
+ CRED_HOOK_UNTRUSTED_ROOT,
+ /** Maximum trust chain length exceeded for certificate */
+ CRED_HOOK_EXCEEDED_PATH_LEN,
+ /** The certificate violates some other kind of policy and gets rejected */
+ CRED_HOOK_POLICY_VIOLATION,
+};
+
+/**
+ * Hook function to invoke on certificate validation errors.
+ *
+ * @param data user data supplied during hook registration
+ * @param type type of validation error/event
+ * @param cert associated certificate
+ */
+typedef void (*credential_hook_t)(void *data, credential_hook_type_t type,
+ certificate_t *cert);
+
+/**
* Manages credentials using credential_sets.
*
* The credential manager is the entry point of the credential framework. It
@@ -263,6 +295,28 @@ struct credential_manager_t {
void (*remove_validator)(credential_manager_t *this, cert_validator_t *vdtr);
/**
+ * Set a hook to call on certain credential validation errors.
+ *
+ * @param hook hook to register, NULL to unregister
+ * @param data data to pass to hook
+ */
+ void (*set_hook)(credential_manager_t *this, credential_hook_t hook,
+ void *data);
+
+ /**
+ * Call the registered credential hook, if any.
+ *
+ * While hooks are usually called by the credential manager itself, some
+ * validator plugins might raise hooks as well if they consider certificates
+ * invalid.
+ *
+ * @param type type of the event
+ * @param cert associated certificate
+ */
+ void (*call_hook)(credential_manager_t *this, credential_hook_type_t type,
+ certificate_t *cert);
+
+ /**
* Destroy a credential_manager instance.
*/
void (*destroy)(credential_manager_t *this);
diff --git a/src/libstrongswan/plugins/constraints/constraints_validator.c b/src/libstrongswan/plugins/constraints/constraints_validator.c
index 83a74299a..62ccc7108 100644
--- a/src/libstrongswan/plugins/constraints/constraints_validator.c
+++ b/src/libstrongswan/plugins/constraints/constraints_validator.c
@@ -533,20 +533,28 @@ METHOD(cert_validator_t, validate, bool,
{
if (!check_pathlen((x509_t*)issuer, pathlen))
{
+ lib->credmgr->call_hook(lib->credmgr, CRED_HOOK_EXCEEDED_PATH_LEN,
+ subject);
return FALSE;
}
if (!check_name_constraints(subject, (x509_t*)issuer))
{
+ lib->credmgr->call_hook(lib->credmgr, CRED_HOOK_POLICY_VIOLATION,
+ subject);
return FALSE;
}
if (!check_policy((x509_t*)subject, (x509_t*)issuer, !pathlen, auth))
{
+ lib->credmgr->call_hook(lib->credmgr, CRED_HOOK_POLICY_VIOLATION,
+ subject);
return FALSE;
}
if (anchor)
{
if (!check_policy_constraints((x509_t*)issuer, pathlen, auth))
{
+ lib->credmgr->call_hook(lib->credmgr,
+ CRED_HOOK_POLICY_VIOLATION, issuer);
return FALSE;
}
}
diff --git a/src/libstrongswan/plugins/revocation/revocation_validator.c b/src/libstrongswan/plugins/revocation/revocation_validator.c
index 44c234559..c8ec3f723 100644
--- a/src/libstrongswan/plugins/revocation/revocation_validator.c
+++ b/src/libstrongswan/plugins/revocation/revocation_validator.c
@@ -691,6 +691,8 @@ METHOD(cert_validator_t, validate, bool,
case VALIDATION_REVOKED:
case VALIDATION_ON_HOLD:
/* has already been logged */
+ lib->credmgr->call_hook(lib->credmgr, CRED_HOOK_REVOKED,
+ subject);
return FALSE;
case VALIDATION_SKIPPED:
DBG2(DBG_CFG, "ocsp check skipped, no ocsp found");
@@ -711,6 +713,8 @@ METHOD(cert_validator_t, validate, bool,
case VALIDATION_REVOKED:
case VALIDATION_ON_HOLD:
/* has already been logged */
+ lib->credmgr->call_hook(lib->credmgr, CRED_HOOK_REVOKED,
+ subject);
return FALSE;
case VALIDATION_FAILED:
case VALIDATION_SKIPPED:
@@ -720,6 +724,8 @@ METHOD(cert_validator_t, validate, bool,
DBG1(DBG_CFG, "certificate status is unknown, crl is stale");
break;
}
+ lib->credmgr->call_hook(lib->credmgr, CRED_HOOK_VALIDATION_FAILED,
+ subject);
}
return TRUE;
}