From c70201f1e3c85badecfbb83092e1983e50ed25e9 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 28 Nov 2019 08:14:59 +0100 Subject: [PATCH] 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. --- src/libstrongswan/credentials/auth_cfg.c | 41 ++++++++++++++++++++---- src/libstrongswan/credentials/auth_cfg.h | 2 ++ 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/libstrongswan/credentials/auth_cfg.c b/src/libstrongswan/credentials/auth_cfg.c index b04627e637..e278bba39b 100644 --- a/src/libstrongswan/credentials/auth_cfg.c +++ b/src/libstrongswan/credentials/auth_cfg.c @@ -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, 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->equals(cert, require_ca)) + 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: diff --git a/src/libstrongswan/credentials/auth_cfg.h b/src/libstrongswan/credentials/auth_cfg.h index 38c40c87dd..4f36b19f29 100644 --- a/src/libstrongswan/credentials/auth_cfg.h +++ b/src/libstrongswan/credentials/auth_cfg.h @@ -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* */ -- 2.47.2