auth-cfg: Add support for identity based CA authentication constraints
authorMartin Willi <martin@strongswan.org>
Thu, 28 Nov 2019 07:14:59 +0000 (08:14 +0100)
committerTobias Brunner <tobias@strongswan.org>
Fri, 6 Dec 2019 09:07:46 +0000 (10:07 +0100)
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
src/libstrongswan/credentials/auth_cfg.h

index b04627e..e278bba 100644 (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, 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:
index 38c40c8..4f36b19 100644 (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* */