auth-cfg: Add support for identity based CA authentication constraints

Enforcing CA based constraints previously required the CA certificate file
to be locally installed. This is problematic from a maintencance perspective
when having many intermediate CAs, and is actually redundant if the client
sends its intermediate cert in the request.

The alternative was to use Distinguished Name matching in the subject
identity to indirectly check for the issuing CA by some RDN field, such as OU.
However, this requires trust in the intermediate CA to issue only certificates
with legitime subject identities.

This new approach checks for an intermediate CA by comparing the issuing
identity. This does not require trust in the intermediate, as long as
a path len constraint prevents that intermediate to issue further
intermediate certificates.
This commit is contained in:
Martin Willi 2019-11-28 08:14:59 +01:00 committed by Tobias Brunner
parent 7035340b21
commit c70201f1e3
2 changed files with 36 additions and 7 deletions

View File

@ -42,6 +42,7 @@ ENUM(auth_rule_names, AUTH_RULE_IDENTITY, AUTH_HELPER_AC_CERT,
"RULE_EAP_VENDOR",
"RULE_XAUTH_BACKEND",
"RULE_XAUTH_IDENTITY",
"AUTH_RULE_CA_IDENTITY",
"RULE_CA_CERT",
"RULE_IM_CERT",
"RULE_SUBJECT_CERT",
@ -88,6 +89,7 @@ static inline bool is_multi_value_rule(auth_rule_t type)
case AUTH_RULE_CRL_VALIDATION:
case AUTH_RULE_GROUP:
case AUTH_RULE_SUBJECT_CERT:
case AUTH_RULE_CA_IDENTITY:
case AUTH_RULE_CA_CERT:
case AUTH_RULE_IM_CERT:
case AUTH_RULE_CERT_POLICY:
@ -226,6 +228,7 @@ static void init_entry(entry_t *this, auth_rule_t type, va_list args)
case AUTH_RULE_XAUTH_BACKEND:
case AUTH_RULE_XAUTH_IDENTITY:
case AUTH_RULE_GROUP:
case AUTH_RULE_CA_IDENTITY:
case AUTH_RULE_CA_CERT:
case AUTH_RULE_IM_CERT:
case AUTH_RULE_SUBJECT_CERT:
@ -287,6 +290,7 @@ static bool entry_equals(entry_t *e1, entry_t *e2)
return c1->equals(c1, c2);
}
case AUTH_RULE_IDENTITY:
case AUTH_RULE_CA_IDENTITY:
case AUTH_RULE_EAP_IDENTITY:
case AUTH_RULE_AAA_IDENTITY:
case AUTH_RULE_XAUTH_IDENTITY:
@ -325,6 +329,7 @@ static void destroy_entry_value(entry_t *entry)
switch (entry->type)
{
case AUTH_RULE_IDENTITY:
case AUTH_RULE_CA_IDENTITY:
case AUTH_RULE_EAP_IDENTITY:
case AUTH_RULE_AAA_IDENTITY:
case AUTH_RULE_GROUP:
@ -406,6 +411,7 @@ static void replace(private_auth_cfg_t *this, entry_enumerator_t *enumerator,
entry->value = (void*)(uintptr_t)va_arg(args, u_int);
break;
case AUTH_RULE_IDENTITY:
case AUTH_RULE_CA_IDENTITY:
case AUTH_RULE_EAP_IDENTITY:
case AUTH_RULE_AAA_IDENTITY:
case AUTH_RULE_XAUTH_BACKEND:
@ -486,6 +492,7 @@ METHOD(auth_cfg_t, get, void*,
case AUTH_RULE_CERT_VALIDATION_SUSPENDED:
return (void*)FALSE;
case AUTH_RULE_IDENTITY:
case AUTH_RULE_CA_IDENTITY:
case AUTH_RULE_EAP_IDENTITY:
case AUTH_RULE_AAA_IDENTITY:
case AUTH_RULE_XAUTH_BACKEND:
@ -808,8 +815,8 @@ METHOD(auth_cfg_t, complies, bool,
enumerator_t *e1, *e2;
bool success = TRUE, group_match = FALSE;
bool ca_match = FALSE, cert_match = FALSE;
identification_t *require_group = NULL;
certificate_t *require_ca = NULL, *require_cert = NULL;
identification_t *require_group = NULL, *require_ca = NULL;
certificate_t *require_cert = NULL;
signature_params_t *ike_scheme = NULL, *scheme = NULL;
u_int strength = 0;
auth_rule_t t1, t2;
@ -824,16 +831,35 @@ METHOD(auth_cfg_t, complies, bool,
case AUTH_RULE_CA_CERT:
case AUTH_RULE_IM_CERT:
{
certificate_t *cert;
certificate_t *cert, *ca;
/* for CA certs, a match of a single cert is sufficient */
require_ca = (certificate_t*)value;
ca = (certificate_t*)value;
require_ca = ca->get_subject(ca);
e2 = create_enumerator(this);
while (e2->enumerate(e2, &t2, &cert))
{
if ((t2 == AUTH_RULE_CA_CERT || t2 == AUTH_RULE_IM_CERT) &&
cert->equals(cert, require_ca))
cert->equals(cert, ca))
{
ca_match = TRUE;
}
}
e2->destroy(e2);
break;
}
case AUTH_RULE_CA_IDENTITY:
{
certificate_t *cert;
require_ca = (identification_t*)value;
e2 = create_enumerator(this);
while (e2->enumerate(e2, &t2, &cert))
{
if ((t2 == AUTH_RULE_CA_CERT || t2 == AUTH_RULE_IM_CERT) &&
cert->has_subject(cert, require_ca))
{
ca_match = TRUE;
}
@ -1138,8 +1164,7 @@ METHOD(auth_cfg_t, complies, bool,
if (log_error)
{
DBG1(DBG_CFG, "constraint check failed: peer not "
"authenticated by CA '%Y'",
require_ca->get_subject(require_ca));
"authenticated by CA '%Y'", require_ca);
}
return FALSE;
}
@ -1205,6 +1230,7 @@ static void merge(private_auth_cfg_t *this, private_auth_cfg_t *other, bool copy
break;
}
case AUTH_RULE_IDENTITY:
case AUTH_RULE_CA_IDENTITY:
case AUTH_RULE_EAP_IDENTITY:
case AUTH_RULE_AAA_IDENTITY:
case AUTH_RULE_GROUP:
@ -1337,6 +1363,7 @@ METHOD(auth_cfg_t, clone_, auth_cfg_t*,
switch (type)
{
case AUTH_RULE_IDENTITY:
case AUTH_RULE_CA_IDENTITY:
case AUTH_RULE_EAP_IDENTITY:
case AUTH_RULE_AAA_IDENTITY:
case AUTH_RULE_GROUP:

View File

@ -84,6 +84,8 @@ enum auth_rule_t {
AUTH_RULE_XAUTH_BACKEND,
/** XAuth identity to use or require, identification_t* */
AUTH_RULE_XAUTH_IDENTITY,
/** subject of certificate authority, identification_t* */
AUTH_RULE_CA_IDENTITY,
/** certificate authority, certificate_t* */
AUTH_RULE_CA_CERT,
/** intermediate certificate in trustchain, certificate_t* */