aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libcharon/plugins/stroke/stroke_config.c47
-rw-r--r--src/libstrongswan/credentials/auth_cfg.c35
-rw-r--r--src/libstrongswan/credentials/credential_manager.c54
3 files changed, 109 insertions, 27 deletions
diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c
index deff25878..5970e7cf3 100644
--- a/src/libcharon/plugins/stroke/stroke_config.c
+++ b/src/libcharon/plugins/stroke/stroke_config.c
@@ -448,25 +448,42 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
identity = identification_create_from_string(id);
if (cert)
{
- certificate = this->cred->load_peer(this->cred, cert);
- if (certificate)
+ enumerator_t *enumerator;
+ bool has_subject = FALSE;
+ certificate_t *first = NULL;
+
+ enumerator = enumerator_create_token(cert, ",", " ");
+ while (enumerator->enumerate(enumerator, &cert))
{
- if (local)
- {
- this->ca->check_for_hash_and_url(this->ca, certificate);
- }
- cfg->add(cfg, AUTH_RULE_SUBJECT_CERT, certificate);
- if (identity->get_type(identity) == ID_ANY ||
- !certificate->has_subject(certificate, identity))
+ certificate = this->cred->load_peer(this->cred, cert);
+ if (certificate)
{
- DBG1(DBG_CFG, " id '%Y' not confirmed by certificate, "
- "defaulting to '%Y'", identity,
- certificate->get_subject(certificate));
- identity->destroy(identity);
- identity = certificate->get_subject(certificate);
- identity = identity->clone(identity);
+ if (local)
+ {
+ this->ca->check_for_hash_and_url(this->ca, certificate);
+ }
+ cfg->add(cfg, AUTH_RULE_SUBJECT_CERT, certificate);
+ if (!first)
+ {
+ first = certificate;
+ }
+ if (identity->get_type(identity) != ID_ANY &&
+ certificate->has_subject(certificate, identity))
+ {
+ has_subject = TRUE;
+ }
}
}
+ enumerator->destroy(enumerator);
+
+ if (first && !has_subject)
+ {
+ DBG1(DBG_CFG, " id '%Y' not confirmed by certificate, "
+ "defaulting to '%Y'", identity, first->get_subject(first));
+ identity->destroy(identity);
+ identity = first->get_subject(first);
+ identity = identity->clone(identity);
+ }
}
if (identity->get_type(identity) != ID_ANY)
{
diff --git a/src/libstrongswan/credentials/auth_cfg.c b/src/libstrongswan/credentials/auth_cfg.c
index a2ffe0295..d2d0a7d72 100644
--- a/src/libstrongswan/credentials/auth_cfg.c
+++ b/src/libstrongswan/credentials/auth_cfg.c
@@ -76,7 +76,6 @@ static inline bool is_multi_value_rule(auth_rule_t type)
case AUTH_RULE_AAA_IDENTITY:
case AUTH_RULE_XAUTH_IDENTITY:
case AUTH_RULE_XAUTH_BACKEND:
- case AUTH_RULE_SUBJECT_CERT:
case AUTH_HELPER_SUBJECT_CERT:
case AUTH_HELPER_SUBJECT_HASH_URL:
case AUTH_RULE_MAX:
@@ -84,6 +83,7 @@ static inline bool is_multi_value_rule(auth_rule_t type)
case AUTH_RULE_OCSP_VALIDATION:
case AUTH_RULE_CRL_VALIDATION:
case AUTH_RULE_GROUP:
+ case AUTH_RULE_SUBJECT_CERT:
case AUTH_RULE_CA_CERT:
case AUTH_RULE_IM_CERT:
case AUTH_RULE_CERT_POLICY:
@@ -503,8 +503,9 @@ METHOD(auth_cfg_t, complies, bool,
private_auth_cfg_t *this, auth_cfg_t *constraints, bool log_error)
{
enumerator_t *e1, *e2;
- bool success = TRUE, group_match = FALSE;
+ bool success = TRUE, group_match = FALSE, cert_match = FALSE;
identification_t *require_group = NULL;
+ certificate_t *require_cert = NULL;
signature_scheme_t scheme = SIGN_UNKNOWN;
u_int strength = 0;
auth_rule_t t1, t2;
@@ -542,20 +543,21 @@ METHOD(auth_cfg_t, complies, bool,
}
case AUTH_RULE_SUBJECT_CERT:
{
- certificate_t *c1, *c2;
+ certificate_t *cert;
- c1 = (certificate_t*)value;
- c2 = get(this, AUTH_RULE_SUBJECT_CERT);
- if (!c2 || !c1->equals(c1, c2))
+ /* for certs, a match of a single cert is sufficient */
+ require_cert = (certificate_t*)value;
+
+ e2 = create_enumerator(this);
+ while (e2->enumerate(e2, &t2, &cert))
{
- success = FALSE;
- if (log_error)
+ if (t2 == AUTH_RULE_SUBJECT_CERT &&
+ cert->equals(cert, require_cert))
{
- DBG1(DBG_CFG, "constraint check failed: peer not "
- "authenticated with peer cert '%Y'.",
- c1->get_subject(c1));
+ cert_match = TRUE;
}
}
+ e2->destroy(e2);
break;
}
case AUTH_RULE_CRL_VALIDATION:
@@ -828,6 +830,17 @@ METHOD(auth_cfg_t, complies, bool,
}
return FALSE;
}
+
+ if (require_cert && !cert_match)
+ {
+ if (log_error)
+ {
+ DBG1(DBG_CFG, "constraint check failed: peer not "
+ "authenticated with peer cert '%Y'.",
+ require_cert->get_subject(require_cert));
+ }
+ return FALSE;
+ }
return success;
}
diff --git a/src/libstrongswan/credentials/credential_manager.c b/src/libstrongswan/credentials/credential_manager.c
index 44eaec62c..f4cd9b9e6 100644
--- a/src/libstrongswan/credentials/credential_manager.c
+++ b/src/libstrongswan/credentials/credential_manager.c
@@ -1083,6 +1083,29 @@ static private_key_t *get_private_by_cert(private_credential_manager_t *this,
return private;
}
+/**
+ * Move the actually used certificate to front, so it gets returned with get()
+ */
+static void prefer_cert(auth_cfg_t *auth, certificate_t *cert)
+{
+ enumerator_t *enumerator;
+ auth_rule_t rule;
+ certificate_t *current;
+
+ enumerator = auth->create_enumerator(auth);
+ while (enumerator->enumerate(enumerator, &rule, &current))
+ {
+ if (rule == AUTH_RULE_SUBJECT_CERT)
+ {
+ current->get_ref(current);
+ auth->replace(auth, enumerator, AUTH_RULE_SUBJECT_CERT, cert);
+ cert = current;
+ }
+ }
+ enumerator->destroy(enumerator);
+ auth->add(auth, AUTH_RULE_SUBJECT_CERT, cert);
+}
+
METHOD(credential_manager_t, get_private, private_key_t*,
private_credential_manager_t *this, key_type_t type, identification_t *id,
auth_cfg_t *auth)
@@ -1091,6 +1114,7 @@ METHOD(credential_manager_t, get_private, private_key_t*,
certificate_t *cert;
private_key_t *private = NULL;
auth_cfg_t *trustchain;
+ auth_rule_t rule;
/* check if this is a lookup by key ID, and do it if so */
if (id && id->get_type(id) == ID_KEY_ID)
@@ -1104,7 +1128,35 @@ METHOD(credential_manager_t, get_private, private_key_t*,
if (auth)
{
- /* if a specific certificate is preferred, check for a matching key */
+ /* try to find a trustchain with one of the configured subject certs */
+ enumerator = auth->create_enumerator(auth);
+ while (enumerator->enumerate(enumerator, &rule, &cert))
+ {
+ if (rule == AUTH_RULE_SUBJECT_CERT)
+ {
+ private = get_private_by_cert(this, cert, type);
+ if (private)
+ {
+ trustchain = build_trustchain(this, cert, auth);
+ if (trustchain)
+ {
+ auth->merge(auth, trustchain, FALSE);
+ prefer_cert(auth, cert->get_ref(cert));
+ trustchain->destroy(trustchain);
+ break;
+ }
+ private->destroy(private);
+ private = NULL;
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+ if (private)
+ {
+ return private;
+ }
+
+ /* if none yielded a trustchain, enforce the first configured cert */
cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
if (cert)
{