aboutsummaryrefslogtreecommitdiffstats
path: root/src/libstrongswan/plugins/constraints/constraints_validator.c
diff options
context:
space:
mode:
authorMartin Willi <martin@revosec.ch>2010-12-09 16:39:07 +0100
committerMartin Willi <martin@revosec.ch>2011-01-05 16:46:00 +0100
commita2b340764fac2021ade280c4bdedb6c7c5f76ee3 (patch)
tree183160a2ee03071b837d3fd9f5eaca890d85bcbc /src/libstrongswan/plugins/constraints/constraints_validator.c
parente6fbe5933bb500de0d7787954c0f8bace42b8f8f (diff)
downloadstrongswan-a2b340764fac2021ade280c4bdedb6c7c5f76ee3.tar.bz2
strongswan-a2b340764fac2021ade280c4bdedb6c7c5f76ee3.tar.xz
Implemented NameConstraint matching in constraints plugin
Diffstat (limited to 'src/libstrongswan/plugins/constraints/constraints_validator.c')
-rw-r--r--src/libstrongswan/plugins/constraints/constraints_validator.c208
1 files changed, 208 insertions, 0 deletions
diff --git a/src/libstrongswan/plugins/constraints/constraints_validator.c b/src/libstrongswan/plugins/constraints/constraints_validator.c
index 7598f2896..bab2535c1 100644
--- a/src/libstrongswan/plugins/constraints/constraints_validator.c
+++ b/src/libstrongswan/plugins/constraints/constraints_validator.c
@@ -49,6 +49,210 @@ static bool check_pathlen(x509_t *issuer, int pathlen)
return TRUE;
}
+/**
+ * Check if a FQDN/RFC822 constraint matches (suffix match)
+ */
+static bool suffix_matches(identification_t *constraint, identification_t *id)
+{
+ chunk_t c, i;
+
+ c = constraint->get_encoding(constraint);
+ i = id->get_encoding(id);
+
+ return i.len >= c.len && chunk_equals(c, chunk_skip(i, i.len - c.len));
+}
+
+/**
+ * Check if a DN constraint matches (RDN prefix match)
+ */
+static bool dn_matches(identification_t *constraint, identification_t *id)
+{
+ enumerator_t *ec, *ei;
+ id_part_t pc, pi;
+ chunk_t cc, ci;
+ bool match = TRUE;
+
+ ec = constraint->create_part_enumerator(constraint);
+ ei = id->create_part_enumerator(id);
+ while (ec->enumerate(ec, &pc, &cc))
+ {
+ if (!ei->enumerate(ei, &pi, &ci) ||
+ pi != pc || !chunk_equals(cc, ci))
+ {
+ match = FALSE;
+ break;
+ }
+ }
+ ec->destroy(ec);
+ ei->destroy(ei);
+
+ return match;
+}
+
+/**
+ * Check if a certificate matches to a NameConstraint
+ */
+static bool name_constraint_matches(identification_t *constraint,
+ certificate_t *cert, bool permitted)
+{
+ x509_t *x509 = (x509_t*)cert;
+ enumerator_t *enumerator;
+ identification_t *id;
+ id_type_t type;
+ bool matches = permitted;
+
+ type = constraint->get_type(constraint);
+ if (type == ID_DER_ASN1_DN)
+ {
+ matches = dn_matches(constraint, cert->get_subject(cert));
+ if (matches != permitted)
+ {
+ return matches;
+ }
+ }
+
+ enumerator = x509->create_subjectAltName_enumerator(x509);
+ while (enumerator->enumerate(enumerator, &id))
+ {
+ if (id->get_type(id) == type)
+ {
+ switch (type)
+ {
+ case ID_FQDN:
+ case ID_RFC822_ADDR:
+ matches = suffix_matches(constraint, id);
+ break;
+ case ID_DER_ASN1_DN:
+ matches = dn_matches(constraint, id);
+ break;
+ default:
+ DBG1(DBG_CFG, "%N NameConstraint matching not implemented",
+ id_type_names, type);
+ matches = FALSE;
+ break;
+ }
+ }
+ if (matches != permitted)
+ {
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ return matches;
+}
+
+/**
+ * Check if a permitted or excluded NameConstraint has been inherited to sub-CA
+ */
+static bool name_constraint_inherited(identification_t *constraint,
+ x509_t *x509, bool permitted)
+{
+ enumerator_t *enumerator;
+ identification_t *id;
+ bool inherited = FALSE;
+ id_type_t type;
+
+ if (!(x509->get_flags(x509) & X509_CA))
+ { /* not a sub-CA, not required */
+ return TRUE;
+ }
+
+ type = constraint->get_type(constraint);
+ enumerator = x509->create_name_constraint_enumerator(x509, permitted);
+ while (enumerator->enumerate(enumerator, &id))
+ {
+ if (id->get_type(id) == type)
+ {
+ switch (type)
+ {
+ case ID_FQDN:
+ case ID_RFC822_ADDR:
+ if (permitted)
+ { /* permitted constraint can be narrowed */
+ inherited = suffix_matches(constraint, id);
+ }
+ else
+ { /* excluded constraint can be widened */
+ inherited = suffix_matches(id, constraint);
+ }
+ break;
+ case ID_DER_ASN1_DN:
+ if (permitted)
+ {
+ inherited = dn_matches(constraint, id);
+ }
+ else
+ {
+ inherited = dn_matches(id, constraint);
+ }
+ break;
+ default:
+ DBG1(DBG_CFG, "%N NameConstraint matching not implemented",
+ id_type_names, type);
+ inherited = FALSE;
+ break;
+ }
+ }
+ if (inherited)
+ {
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ return inherited;
+}
+
+/**
+ * Check name constraints
+ */
+static bool check_name_constraints(certificate_t *subject, x509_t *issuer)
+{
+ enumerator_t *enumerator;
+ identification_t *constraint;
+
+ enumerator = issuer->create_name_constraint_enumerator(issuer, TRUE);
+ while (enumerator->enumerate(enumerator, &constraint))
+ {
+ if (!name_constraint_matches(constraint, subject, TRUE))
+ {
+ DBG1(DBG_CFG, "certificate '%Y' does not match permitted name "
+ "constraint '%Y'", subject->get_subject(subject), constraint);
+ enumerator->destroy(enumerator);
+ return FALSE;
+ }
+ if (!name_constraint_inherited(constraint, (x509_t*)subject, TRUE))
+ {
+ DBG1(DBG_CFG, "intermediate CA '%Y' does not inherit permitted name "
+ "constraint '%Y'", subject->get_subject(subject), constraint);
+ enumerator->destroy(enumerator);
+ return FALSE;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ enumerator = issuer->create_name_constraint_enumerator(issuer, FALSE);
+ while (enumerator->enumerate(enumerator, &constraint))
+ {
+ if (name_constraint_matches(constraint, subject, FALSE))
+ {
+ DBG1(DBG_CFG, "certificate '%Y' matches excluded name "
+ "constraint '%Y'", subject->get_subject(subject), constraint);
+ enumerator->destroy(enumerator);
+ return FALSE;
+ }
+ if (!name_constraint_inherited(constraint, (x509_t*)subject, FALSE))
+ {
+ DBG1(DBG_CFG, "intermediate CA '%Y' does not inherit excluded name "
+ "constraint '%Y'", subject->get_subject(subject), constraint);
+ enumerator->destroy(enumerator);
+ return FALSE;
+ }
+ }
+ enumerator->destroy(enumerator);
+ return TRUE;
+}
+
METHOD(cert_validator_t, validate, bool,
private_constraints_validator_t *this, certificate_t *subject,
certificate_t *issuer, bool online, int pathlen, auth_cfg_t *auth)
@@ -60,6 +264,10 @@ METHOD(cert_validator_t, validate, bool,
{
return FALSE;
}
+ if (!check_name_constraints(subject, (x509_t*)issuer))
+ {
+ return FALSE;
+ }
}
return TRUE;
}