Merge branch 'ca-identity-constraint'
This adds a new constraint for vici/swanctl.conf that enforces that the certificate chain of the remote peer contains a CA certificate with a specific identity. This is similar to the existing CA constraints, but doesn't require that the CA certificate is locally installed, for instance, intermediate CA certificates received by the peers. Wildcard identity matching (e.g. "..., OU=Research, CN=*") could also be used for the latter, but requires trust in the intermediate CA to only issue certificates with legitimate subject DNs (e.g. the "Sales" CA must not issue certificates with "OU=Research"). With the new constraint that's not necessary as long as a path length constraint prevents intermediate CAs from issuing further intermediate CAs.
This commit is contained in:
commit
96b8fa72b3
|
@ -347,6 +347,7 @@ static void log_auth(auth_cfg_t *auth)
|
|||
union {
|
||||
uintptr_t u;
|
||||
identification_t *id;
|
||||
certificate_t *cert;
|
||||
char *str;
|
||||
} v;
|
||||
|
||||
|
@ -373,6 +374,9 @@ static void log_auth(auth_cfg_t *auth)
|
|||
case AUTH_RULE_IDENTITY:
|
||||
DBG2(DBG_CFG, " id = %Y", v.id);
|
||||
break;
|
||||
case AUTH_RULE_CA_IDENTITY:
|
||||
DBG2(DBG_CFG, " ca_id = %Y", v.id);
|
||||
break;
|
||||
case AUTH_RULE_AAA_IDENTITY:
|
||||
DBG2(DBG_CFG, " aaa_id = %Y", v.id);
|
||||
break;
|
||||
|
@ -385,6 +389,12 @@ static void log_auth(auth_cfg_t *auth)
|
|||
case AUTH_RULE_GROUP:
|
||||
DBG2(DBG_CFG, " group = %Y", v.id);
|
||||
break;
|
||||
case AUTH_RULE_SUBJECT_CERT:
|
||||
DBG2(DBG_CFG, " cert = %Y", v.cert->get_subject(v.cert));
|
||||
break;
|
||||
case AUTH_RULE_CA_CERT:
|
||||
DBG2(DBG_CFG, " cacert = %Y", v.cert->get_subject(v.cert));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1360,6 +1370,15 @@ CALLBACK(parse_ike_id, bool,
|
|||
return parse_id(cfg, AUTH_RULE_IDENTITY, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse CA identity constraint
|
||||
*/
|
||||
CALLBACK(parse_ca_id, bool,
|
||||
auth_cfg_t *cfg, chunk_t v)
|
||||
{
|
||||
return parse_id(cfg, AUTH_RULE_CA_IDENTITY, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse AAA identity
|
||||
*/
|
||||
|
@ -1755,6 +1774,7 @@ CALLBACK(auth_kv, bool,
|
|||
parse_rule_t rules[] = {
|
||||
{ "auth", parse_auth, auth->cfg },
|
||||
{ "id", parse_ike_id, auth->cfg },
|
||||
{ "ca_id", parse_ca_id, auth->cfg },
|
||||
{ "aaa_id", parse_aaa_id, auth->cfg },
|
||||
{ "eap_id", parse_eap_id, auth->cfg },
|
||||
{ "xauth_id", parse_xauth_id, auth->cfg },
|
||||
|
|
|
@ -765,6 +765,9 @@ static void build_auth_cfgs(peer_cfg_t *peer_cfg, bool local, vici_builder_t *b)
|
|||
case AUTH_RULE_IDENTITY:
|
||||
b->add_kv(b, "id", "%Y", v.id);
|
||||
break;
|
||||
case AUTH_RULE_CA_IDENTITY:
|
||||
b->add_kv(b, "ca_id", "%Y", v.id);
|
||||
break;
|
||||
case AUTH_RULE_AAA_IDENTITY:
|
||||
b->add_kv(b, "aaa_id", "%Y", v.id);
|
||||
break;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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* */
|
||||
|
|
|
@ -183,6 +183,10 @@ CALLBACK(conn_sn, int,
|
|||
{
|
||||
printf(" id: %s\n", auth->get(auth, "id"));
|
||||
}
|
||||
if (auth->get(auth, "ca_id"))
|
||||
{
|
||||
printf(" ca_id: %s\n", auth->get(auth, "ca_id"));
|
||||
}
|
||||
if (auth->get(auth, "eap_id"))
|
||||
{
|
||||
printf(" eap_id: %s\n", auth->get(auth, "eap_id"));
|
||||
|
|
|
@ -593,6 +593,16 @@ connections.<conn>.remote<suffix>.cacert<suffix>.slot =
|
|||
connections.<conn>.remote<suffix>.cacert<suffix>.module =
|
||||
Optional PKCS#11 module name.
|
||||
|
||||
connections.<conn>.remote<suffix>.ca_id =
|
||||
Identity in CA certificate to accept for authentication.
|
||||
|
||||
The specified identity must be contained in one (intermediate) CA
|
||||
of the remote peer trustchain, either as subject or as subjectAltName.
|
||||
This has the same effect as specifying _cacerts_ to force clients under
|
||||
a CA to specific connections; it does not require the CA certificate to
|
||||
be available locally, and can be received from the peer during the
|
||||
IKE exchange.
|
||||
|
||||
connections.<conn>.remote<suffix>.pubkeys =
|
||||
Comma separated list of raw public keys to accept for authentication.
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ connections {
|
|||
}
|
||||
remote {
|
||||
auth = pubkey
|
||||
id = "C=CH, O=strongSwan Project, OU=Research, CN=*"
|
||||
ca_id = "C=CH, O=strongSwan Project, OU=Research, CN=Research CA"
|
||||
}
|
||||
children {
|
||||
alice {
|
||||
|
@ -32,7 +32,7 @@ connections {
|
|||
}
|
||||
remote {
|
||||
auth = pubkey
|
||||
id = "C=CH, O=strongSwan Project, OU=Sales, CN=*"
|
||||
ca_id = "C=CH, O=strongSwan Project, OU=Sales, CN=Sales CA"
|
||||
}
|
||||
children {
|
||||
venus {
|
||||
|
|
Loading…
Reference in New Issue