Check requireExplicitPolicy in constraints plugin
authorMartin Willi <martin@revosec.ch>
Wed, 22 Dec 2010 09:38:06 +0000 (10:38 +0100)
committerMartin Willi <martin@revosec.ch>
Wed, 5 Jan 2011 15:46:04 +0000 (16:46 +0100)
src/libstrongswan/plugins/constraints/constraints_validator.c

index fa04527..651f41d 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <debug.h>
 #include <asn1/asn1.h>
+#include <utils/linked_list.h>
 #include <credentials/certificates/x509.h>
 
 typedef struct private_constraints_validator_t private_constraints_validator_t;
@@ -291,9 +292,9 @@ static bool has_policy(x509_t *issuer, chunk_t oid)
 }
 
 /**
- * Check certificatePolicies
+ * Check certificatePolicies.
  */
-static bool check_policy(x509_t *subject, x509_t *issuer, int pathlen,
+static bool check_policy(x509_t *subject, x509_t *issuer, bool check,
                                                 auth_cfg_t *auth)
 {
        certificate_t *cert = (certificate_t*)subject;
@@ -318,32 +319,114 @@ static bool check_policy(x509_t *subject, x509_t *issuer, int pathlen,
        }
        enumerator->destroy(enumerator);
 
-       enumerator = subject->create_cert_policy_enumerator(subject);
-       while (enumerator->enumerate(enumerator, &policy))
+       if (check)
        {
-               if (!has_policy(issuer, policy->oid))
-               {
-                       oid = asn1_oid_to_string(policy->oid);
-                       DBG1(DBG_CFG, "policy %s missing in issuing certificate '%Y'",
-                                oid, cert->get_issuer(cert));
-                       free(oid);
-                       enumerator->destroy(enumerator);
-                       return FALSE;
-               }
-               if (pathlen == 0)
+               enumerator = subject->create_cert_policy_enumerator(subject);
+               while (enumerator->enumerate(enumerator, &policy))
                {
-                       oid = asn1_oid_to_string(policy->oid);
-                       if (oid)
+                       if (!has_policy(issuer, policy->oid))
                        {
-                               auth->add(auth, AUTH_RULE_CERT_POLICY, oid);
+                               oid = asn1_oid_to_string(policy->oid);
+                               DBG1(DBG_CFG, "policy %s missing in issuing certificate '%Y'",
+                                        oid, cert->get_issuer(cert));
+                               free(oid);
+                               enumerator->destroy(enumerator);
+                               return FALSE;
+                       }
+                       if (auth)
+                       {
+                               oid = asn1_oid_to_string(policy->oid);
+                               if (oid)
+                               {
+                                       auth->add(auth, AUTH_RULE_CERT_POLICY, oid);
+                               }
                        }
                }
+               enumerator->destroy(enumerator);
        }
-       enumerator->destroy(enumerator);
 
        return TRUE;
 }
 
+/**
+ * Check len certificates in trustchain for inherited policies
+ */
+static bool has_policy_chain(linked_list_t *chain, x509_t *subject, int len)
+{
+       enumerator_t *enumerator;
+       x509_t *issuer;
+       bool valid = TRUE;
+
+       enumerator = chain->create_enumerator(chain);
+       while (len-- > 0 && enumerator->enumerate(enumerator, &issuer))
+       {
+               if (!check_policy(subject, issuer, TRUE, NULL))
+               {
+                       valid = FALSE;
+                       break;
+               }
+               subject = issuer;
+       }
+       enumerator->destroy(enumerator);
+       return valid;
+}
+
+/**
+ * Check if required explicit policies are given in a path
+ */
+static bool check_explicit_policy(x509_t *issuer, int pathlen, auth_cfg_t *auth)
+{
+       certificate_t *subject;
+       bool valid = TRUE;
+
+       subject = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
+       if (subject)
+       {
+               if (subject->get_type(subject) == CERT_X509)
+               {
+                       enumerator_t *enumerator;
+                       linked_list_t *chain;
+                       certificate_t *cert;
+                       auth_rule_t rule;
+                       x509_t *x509;
+                       int len = 0, expl;
+
+                       /* prepare trustchain to validate */
+                       chain = linked_list_create();
+                       enumerator = auth->create_enumerator(auth);
+                       while (enumerator->enumerate(enumerator, &rule, &cert))
+                       {
+                               if (rule == AUTH_RULE_IM_CERT &&
+                                       cert->get_type(cert) == CERT_X509)
+                               {
+                                       chain->insert_last(chain, cert);
+                               }
+                       }
+                       enumerator->destroy(enumerator);
+                       chain->insert_last(chain, issuer);
+
+                       /* search for requireExplicitPolicy constraints */
+                       enumerator = chain->create_enumerator(chain);
+                       while (enumerator->enumerate(enumerator, &x509))
+                       {
+                               expl = x509->get_policyConstraint(x509, FALSE);
+                               if (expl != X509_NO_CONSTRAINT)
+                               {
+                                       if (!has_policy_chain(chain, (x509_t*)subject, len - expl))
+                                       {
+                                               valid = FALSE;
+                                               break;
+                                       }
+                               }
+                               len++;
+                       }
+                       enumerator->destroy(enumerator);
+                       chain->destroy(chain);
+               }
+       }
+       return valid;
+}
+
 METHOD(cert_validator_t, validate, bool,
        private_constraints_validator_t *this, certificate_t *subject,
        certificate_t *issuer, bool online, int pathlen, bool anchor,
@@ -360,10 +443,17 @@ METHOD(cert_validator_t, validate, bool,
                {
                        return FALSE;
                }
-               if (!check_policy((x509_t*)subject, (x509_t*)issuer, pathlen, auth))
+               if (!check_policy((x509_t*)subject, (x509_t*)issuer, !pathlen, auth))
                {
                        return FALSE;
                }
+               if (anchor)
+               {
+                       if (!check_explicit_policy((x509_t*)issuer, pathlen, auth))
+                       {
+                               return FALSE;
+                       }
+               }
        }
        return TRUE;
 }