Merge branch 'multi-cert'

Allows the configuration of multiple certificates in leftcert, and select
the correct certificate to use based on the received certificate requests.
This commit is contained in:
Martin Willi
2013-03-01 11:35:32 +01:00
4 changed files with 113 additions and 27 deletions
+32 -15
View File
@@ -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)
certificate = this->cred->load_peer(this->cred, cert);
if (certificate)
{
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))
{
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)
{
+24 -11
View File
@@ -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;
}
@@ -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)
{