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
commit e82deaf6ce
4 changed files with 113 additions and 27 deletions

View File

@ -618,6 +618,10 @@ connection. See ipsec.secrets(5) for details about smartcard definitions.
is required only if selecting the certificate with
.B leftid
is not sufficient, for example if multiple certificates use the same subject.
.br
Multiple certificate paths or PKCS#11 backends can be specified in a comma
separated list. The daemon chooses the certificate based on the received
certificate requests if possible before enforcing the first.
.TP
.BR leftcert2 " = <path>"
Same as

View File

@ -447,6 +447,13 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
/* add identity and peer certificate */
identity = identification_create_from_string(id);
if (cert)
{
enumerator_t *enumerator;
bool has_subject = FALSE;
certificate_t *first = NULL;
enumerator = enumerator_create_token(cert, ",", " ");
while (enumerator->enumerate(enumerator, &cert))
{
certificate = this->cred->load_peer(this->cred, cert);
if (certificate)
@ -456,18 +463,28 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
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))
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,
certificate->get_subject(certificate));
"defaulting to '%Y'", identity, first->get_subject(first));
identity->destroy(identity);
identity = certificate->get_subject(certificate);
identity = first->get_subject(first);
identity = identity->clone(identity);
}
}
}
if (identity->get_type(identity) != ID_ANY)
{
cfg->add(cfg, AUTH_RULE_IDENTITY, identity);

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;
}

View File

@ -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)
{