constraints: Properly validate name constraints according to RFC 5280

The previous code was in a way too simple which resulted in it being too
strict.  For instance, it enforced that intermediate CA certificates
inherited the name constraints of their parents.  That's not required by
RFC 5280 and prevented e.g. adding constraints in an intermediate CA
certificate that's followed by another that doesn't contain any
name constraints.  That's perfectly fine as the set of constraints
specified by the parent continue to apply to that CA certificate and
the children it issues.

Name constraints were previously also applied to all identities of a
matching type, which is way too strict except for some very simple
cases.  It basically prevented multiple constraints of the same type
as e.g. an intermediate CA certificate that has permitted name constraints
for example.org and example.com couldn't issue acceptable certificates
because any SAN with one domain would get rejected by the other
constraint.  According to RFC 5280 matching one constraint is enough.

Also fixed is an issue with name constraints for IP addresses which were
previously only supported for a single level.
This commit is contained in:
Tobias Brunner
2024-03-12 09:14:44 +01:00
parent ea6a6344d3
commit b29be6029e
2 changed files with 816 additions and 203 deletions
@@ -1,4 +1,5 @@
/* /*
* Copyright (C) 2023-2024 Tobias Brunner
* Copyright (C) 2010 Martin Willi * Copyright (C) 2010 Martin Willi
* *
* Copyright (C) secunet Security Networks AG * Copyright (C) secunet Security Networks AG
@@ -18,6 +19,8 @@
#include <utils/debug.h> #include <utils/debug.h>
#include <asn1/asn1.h> #include <asn1/asn1.h>
#include <collections/array.h>
#include <collections/hashtable.h>
#include <collections/linked_list.h> #include <collections/linked_list.h>
#include <credentials/certificates/x509.h> #include <credentials/certificates/x509.h>
@@ -101,10 +104,14 @@ static bool email_matches(identification_t *constraint, identification_t *id)
return chunk_equals(c, i); return chunk_equals(c, i);
} }
diff = chunk_create(i.ptr, i.len - c.len); diff = chunk_create(i.ptr, i.len - c.len);
if (!diff.len || !chunk_equals(c, chunk_skip(i, diff.len))) if (!chunk_equals(c, chunk_skip(i, diff.len)))
{ {
return FALSE; return FALSE;
} }
if (!diff.len)
{
return TRUE;
}
if (c.ptr[0] == '.') if (c.ptr[0] == '.')
{ /* constraint is domain, suffix match */ { /* constraint is domain, suffix match */
return TRUE; return TRUE;
@@ -144,51 +151,80 @@ static bool dn_matches(identification_t *constraint, identification_t *id)
} }
/** /**
* Check if the given identity type matches the type of NameConstraint * Check if a new permitted or excluded NameConstraint is matching an
* existing one
*/ */
static bool type_matches(id_type_t constraint, id_type_t id) static bool name_constraint_matches(identification_t *existing,
identification_t *new, bool permitted)
{ {
switch (constraint) identification_t *a, *b;
bool matching = FALSE;
if (permitted)
{ /* permitted constraint can be narrowed */
a = existing;
b = new;
}
else
{ /* excluded constraint can be widened */
a = new;
b = existing;
}
switch (existing->get_type(existing))
{ {
case ID_FQDN: case ID_FQDN:
matching = fqdn_matches(a, b);
break;
case ID_RFC822_ADDR: case ID_RFC822_ADDR:
matching = email_matches(a, b);
break;
case ID_DER_ASN1_DN: case ID_DER_ASN1_DN:
return constraint == id; matching = dn_matches(a, b);
break;
case ID_IPV4_ADDR_SUBNET: case ID_IPV4_ADDR_SUBNET:
return id == ID_IPV4_ADDR;
case ID_IPV6_ADDR_SUBNET: case ID_IPV6_ADDR_SUBNET:
return id == ID_IPV6_ADDR; matching = b->matches(b, a);
break;
default: default:
return FALSE; /* shouldn't happen */
matching = FALSE;
break;
}
return matching;
}
/**
* Get the name constraint type from an identity type
*/
static id_type_t constraint_type_from_id(id_type_t id)
{
switch (id)
{
case ID_IPV4_ADDR:
return ID_IPV4_ADDR_SUBNET;
case ID_IPV6_ADDR:
return ID_IPV6_ADDR_SUBNET;
default:
return id;
} }
} }
/** /**
* Check if a certificate matches to a NameConstraint * Check if the given identity matches any of the given name constraints
*/ */
static bool name_constraint_matches(identification_t *constraint, static bool id_matches_constraints(certificate_t *cert, identification_t *id,
certificate_t *cert, bool permitted) array_t *constraints, bool permitted)
{ {
x509_t *x509 = (x509_t*)cert;
enumerator_t *enumerator; enumerator_t *enumerator;
identification_t *id; identification_t *subject, *constraint;
id_type_t type; id_type_t type;
bool matches = permitted; bool matches = FALSE;
type = constraint->get_type(constraint); subject = cert->get_subject(cert);
if (type == ID_DER_ASN1_DN) type = id->get_type(id);
{
matches = dn_matches(constraint, cert->get_subject(cert));
if (matches != permitted)
{
return matches;
}
}
enumerator = x509->create_subjectAltName_enumerator(x509); enumerator = array_create_enumerator(constraints);
while (enumerator->enumerate(enumerator, &id)) while (enumerator->enumerate(enumerator, &constraint))
{
if (type_matches(type, id->get_type(id)))
{ {
switch (type) switch (type)
{ {
@@ -201,134 +237,386 @@ static bool name_constraint_matches(identification_t *constraint,
case ID_DER_ASN1_DN: case ID_DER_ASN1_DN:
matches = dn_matches(constraint, id); matches = dn_matches(constraint, id);
break; break;
case ID_IPV4_ADDR_SUBNET: case ID_IPV4_ADDR:
case ID_IPV6_ADDR_SUBNET: case ID_IPV6_ADDR:
matches = id->matches(id, constraint); matches = id->matches(id, constraint);
break; break;
default: default:
DBG1(DBG_CFG, "%N NameConstraint matching not implemented", /* shouldn't happen */
id_type_names, type); break;
matches = FALSE; }
if (matches)
{
if (!permitted)
{
if (id->equals(id, subject))
{
DBG1(DBG_CFG, "subject of certificate '%Y' matches excluded "
"name constraint '%Y'", subject, constraint);
}
else
{
DBG1(DBG_CFG, "subject alternative name '%Y' of certificate "
"'%Y' matches excluded name constraint '%Y'",
id, subject, constraint);
}
}
break; break;
} }
} }
enumerator->destroy(enumerator);
if (!matches && permitted)
{
if (id->equals(id, subject))
{
DBG1(DBG_CFG, "subject of certificate '%Y' does not match any "
"permitted name constraints", subject);
}
else
{
DBG1(DBG_CFG, "subject alternative name '%Y' of certificate '%Y' "
"does not match any permitted name constraints", id, subject);
}
}
return matches;
}
/**
* Check if a certificate matches the given permitted/excluded name constraints
*/
static bool cert_matches_constraints(x509_t *x509, hashtable_t *types,
bool permitted)
{
certificate_t *cert = (certificate_t*)x509;
array_t *constraints;
enumerator_t *enumerator;
identification_t *id;
id_type_t type;
bool matches = permitted;
constraints = types->get(types, (void*)(uintptr_t)ID_DER_ASN1_DN);
if (constraints)
{
matches = id_matches_constraints(cert, cert->get_subject(cert),
constraints, permitted);
if (matches != permitted)
{
return matches;
}
}
enumerator = x509->create_subjectAltName_enumerator(x509);
while (enumerator->enumerate(enumerator, &id))
{
type = constraint_type_from_id(id->get_type(id));
constraints = types->get(types, (void*)(uintptr_t)type);
if (constraints)
{
matches = id_matches_constraints(cert, id, constraints, permitted);
if (matches != permitted) if (matches != permitted)
{ {
break; break;
} }
} }
}
enumerator->destroy(enumerator); enumerator->destroy(enumerator);
return matches; return matches;
} }
/** /**
* Check if a permitted or excluded NameConstraint has been inherited to sub-CA * Validate the names in the given certificate against the current constraints
*/ */
static bool name_constraint_inherited(identification_t *constraint, static bool name_constraints_match(x509_t *x509, hashtable_t *permitted,
x509_t *x509, bool permitted) hashtable_t *excluded)
{ {
enumerator_t *enumerator; if (permitted && !cert_matches_constraints(x509, permitted, TRUE))
identification_t *id, *a, *b; {
bool inherited = FALSE; return FALSE;
id_type_t type; }
if (excluded && cert_matches_constraints(x509, excluded, FALSE))
if (!(x509->get_flags(x509) & X509_CA)) {
{ /* not a sub-CA, not required */ return FALSE;
}
return TRUE; return TRUE;
} }
/**
* Destroy name constraints (callback for hashtable_t::destroy_function())
*/
CALLBACK(destroy_constraints, void,
array_t *this, const void *key)
{
array_destroy(this);
}
/**
* Hashtable hash function
*/
static u_int id_type_hash(const void *key)
{
uintptr_t id = (uintptr_t)key;
return chunk_hash(chunk_from_thing(id));
}
/**
* Hashtable equals function
*/
static bool id_type_equals(const void *a, const void *b)
{
return (uintptr_t)a == (uintptr_t)b;
}
/**
* Collect name constraints (permitted or excluded) of each supported type
* from the given certificate
*/
static bool collect_constraints(x509_t *x509, bool permitted, hashtable_t **out)
{
hashtable_t *collected;
enumerator_t *enumerator;
identification_t *constraint;
array_t *constraints;
id_type_t type;
bool success = TRUE;
collected = hashtable_create(id_type_hash, id_type_equals, 8);
type = constraint->get_type(constraint);
enumerator = x509->create_name_constraint_enumerator(x509, permitted); enumerator = x509->create_name_constraint_enumerator(x509, permitted);
while (enumerator->enumerate(enumerator, &id)) while (enumerator->enumerate(enumerator, &constraint))
{ {
if (id->get_type(id) == type) type = constraint->get_type(constraint);
{
if (permitted)
{ /* permitted constraint can be narrowed */
a = constraint;
b = id;
}
else
{ /* excluded constraint can be widened */
a = id;
b = constraint;
}
switch (type) switch (type)
{ {
case ID_FQDN: case ID_FQDN:
inherited = fqdn_matches(a, b);
break;
case ID_RFC822_ADDR: case ID_RFC822_ADDR:
inherited = email_matches(a, b);
break;
case ID_DER_ASN1_DN: case ID_DER_ASN1_DN:
inherited = dn_matches(a, b); case ID_IPV4_ADDR_SUBNET:
case ID_IPV6_ADDR_SUBNET:
break; break;
default: default:
DBG1(DBG_CFG, "%N NameConstraint matching not implemented", DBG1(DBG_CFG, "%N NameConstraint not supported",
id_type_names, type); id_type_names, type);
inherited = FALSE; success = FALSE;
break; break;
} }
} if (!success)
if (inherited)
{ {
break; break;
} }
constraints = collected->get(collected, (void*)(uintptr_t)type);
if (!constraints)
{
constraints = array_create(0, 8);
collected->put(collected, (void*)(uintptr_t)type, constraints);
}
array_insert(constraints, ARRAY_TAIL, constraint);
} }
enumerator->destroy(enumerator); enumerator->destroy(enumerator);
return inherited;
if (success)
{
*out = collected;
}
else
{
collected->destroy_function(collected, destroy_constraints);
}
return success;
}
/**
* Merge existing and new permitted/excluded name constraints
*/
static void merge_constraints(certificate_t *cert, array_t *existing_constraints,
array_t *new_constraints, bool permitted)
{
enumerator_t *enumerator, *new;
identification_t *constraint, *new_constraint;
if (permitted)
{
array_t *to_move = NULL;
enumerator = array_create_enumerator(existing_constraints);
while (enumerator->enumerate(enumerator, &constraint))
{
new = array_create_enumerator(new_constraints);
while (new->enumerate(new, &new_constraint))
{
if (name_constraint_matches(constraint, new_constraint, TRUE))
{
array_insert_create(&to_move, ARRAY_TAIL, new_constraint);
array_remove_at(new_constraints, new);
}
}
new->destroy(new);
/* remove the existing constraint. if it was matched, it gets
* replaced by the moved equal/narrower constraints, if not, it's
* not permitted anymore */
array_remove_at(existing_constraints, enumerator);
}
enumerator->destroy(enumerator);
if (to_move)
{
while (array_remove(to_move, ARRAY_HEAD, &new_constraint))
{
array_insert(existing_constraints, ARRAY_TAIL, new_constraint);
}
array_destroy(to_move);
}
/* report ignored constraints that would widen the permitted set */
while (array_remove(new_constraints, ARRAY_HEAD, &new_constraint))
{
DBG1(DBG_CFG, "ignoring name constraint '%Y' in certificate "
"'%Y' that's not permitted by parent CAs",
new_constraint, cert->get_subject(cert));
}
}
else
{
/* this is simpler as we basically adopt all new constraints, we just
* check if we can remove a constraint that gets widened */
enumerator = array_create_enumerator(existing_constraints);
while (enumerator->enumerate(enumerator, &constraint))
{
new = array_create_enumerator(new_constraints);
while (new->enumerate(new, &new_constraint))
{
if (name_constraint_matches(constraint, new_constraint, FALSE))
{
/* remove the existing constraint if it is matched, it
* gets replaced by an equal/wider constraint */
array_remove_at(existing_constraints, enumerator);
break;
}
}
new->destroy(new);
}
enumerator->destroy(enumerator);
/* add all new constraints to the list */
while (array_remove(new_constraints, ARRAY_HEAD, &new_constraint))
{
array_insert(existing_constraints, ARRAY_TAIL, new_constraint);
}
}
}
/**
* Update the set of permitted/excluded name constraints
*/
static bool update_name_constraints(x509_t *x509, hashtable_t **existing,
bool permitted)
{
enumerator_t *enumerator;
hashtable_t *collected;
array_t *existing_constraints, *new_constraints;
void *type;
if (!(x509->get_flags(x509) & X509_CA))
{
/* ignore end-entity certificates */
return TRUE;
}
if (!collect_constraints(x509, permitted, &collected))
{
return FALSE;
}
if (collected->get_count(collected))
{
if (!*existing)
{
/* adopt all constraints if we haven't any yet */
*existing = collected;
collected = NULL;
}
else
{
/* merge sets of constraints for each type */
enumerator = collected->create_enumerator(collected);
while (enumerator->enumerate(enumerator, &type, &new_constraints))
{
existing_constraints = (*existing)->get(*existing, type);
if (existing_constraints)
{
/* merge constraints of known types, either allowing them to
* get narrowed or widened */
merge_constraints((certificate_t*)x509, existing_constraints,
new_constraints, permitted);
}
else
{
/* adopt constraints for new types */
collected->remove_at(collected, enumerator);
(*existing)->put(*existing, type, new_constraints);
}
}
enumerator->destroy(enumerator);
}
}
DESTROY_FUNCTION_IF(collected, destroy_constraints);
return TRUE;
} }
/** /**
* Check name constraints * Check name constraints
*/ */
static bool check_name_constraints(certificate_t *subject, x509_t *issuer) static bool check_name_constraints(x509_t *issuer, u_int pathlen,
auth_cfg_t *auth, certificate_t **violator)
{ {
enumerator_t *enumerator; enumerator_t *enumerator;
identification_t *constraint; linked_list_t *chain;
hashtable_t *permitted = NULL, *excluded = NULL;
certificate_t *subject, *cert;
auth_rule_t rule;
x509_t *x509;
int len = 0;
bool valid = TRUE;
enumerator = issuer->create_name_constraint_enumerator(issuer, TRUE); subject = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
while (enumerator->enumerate(enumerator, &constraint)) if (!subject || subject->get_type(subject) != CERT_X509)
{ {
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; return TRUE;
}
/* prepare trustchain to validate name constraints top-down */
chain = linked_list_create_with_items(subject, NULL);
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_first(chain, cert);
}
}
enumerator->destroy(enumerator);
chain->insert_first(chain, issuer);
enumerator = chain->create_enumerator(chain);
while (enumerator->enumerate(enumerator, &x509))
{
if ((len > 0 && !name_constraints_match(x509, permitted, excluded)) ||
!update_name_constraints(x509, &permitted, TRUE) ||
!update_name_constraints(x509, &excluded, FALSE))
{
valid = FALSE;
*violator = (certificate_t*)x509;
break;
}
len++;
}
enumerator->destroy(enumerator);
DESTROY_FUNCTION_IF(permitted, destroy_constraints);
DESTROY_FUNCTION_IF(excluded, destroy_constraints);
chain->destroy(chain);
return valid;
} }
/** /**
@@ -690,14 +978,16 @@ METHOD(cert_validator_t, validate, bool,
subject); subject);
return FALSE; return FALSE;
} }
if (!check_name_constraints(subject, (x509_t*)issuer))
{
lib->credmgr->call_hook(lib->credmgr, CRED_HOOK_POLICY_VIOLATION,
subject);
return FALSE;
}
if (anchor) if (anchor)
{ {
certificate_t *violator;
if (!check_name_constraints((x509_t*)issuer, pathlen, auth, &violator))
{
lib->credmgr->call_hook(lib->credmgr,
CRED_HOOK_POLICY_VIOLATION, violator);
return FALSE;
}
if (!check_policy_constraints((x509_t*)issuer, pathlen, auth)) if (!check_policy_constraints((x509_t*)issuer, pathlen, auth))
{ {
lib->credmgr->call_hook(lib->credmgr, lib->credmgr->call_hook(lib->credmgr,
+404 -81
View File
@@ -68,15 +68,15 @@ static char keydata[] = {
/** /**
* Issue a certificate with permitted/excluded name constraints * Issue a certificate with permitted/excluded name constraints
*/ */
static certificate_t* create_cert(certificate_t *ca, char *subject, char *san, static certificate_t* create_cert_lists(certificate_t *ca, char *subject,
x509_flag_t flags, identification_t *permitted, linked_list_t *sans, x509_flag_t flags,
identification_t *excluded) linked_list_t *permitted,
linked_list_t *excluded)
{ {
private_key_t *privkey; private_key_t *privkey;
public_key_t *pubkey; public_key_t *pubkey;
certificate_t *cert; certificate_t *cert;
identification_t *id; identification_t *id;
linked_list_t *plist, *elist, *sans;
privkey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, privkey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
BUILD_BLOB_ASN1_DER, chunk_from_thing(keydata), BUILD_BLOB_ASN1_DER, chunk_from_thing(keydata),
@@ -84,6 +84,39 @@ static certificate_t* create_cert(certificate_t *ca, char *subject, char *san,
ck_assert(privkey); ck_assert(privkey);
pubkey = privkey->get_public_key(privkey); pubkey = privkey->get_public_key(privkey);
ck_assert(pubkey); ck_assert(pubkey);
id = identification_create_from_string(subject);
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
BUILD_SIGNING_KEY, privkey,
BUILD_PUBLIC_KEY, pubkey,
BUILD_SUBJECT, id,
BUILD_X509_FLAG, flags,
BUILD_SIGNING_CERT, ca,
BUILD_SUBJECT_ALTNAMES, sans,
BUILD_PERMITTED_NAME_CONSTRAINTS, permitted,
BUILD_EXCLUDED_NAME_CONSTRAINTS, excluded,
BUILD_END);
ck_assert(cert);
id->destroy(id);
sans->destroy_offset(sans, offsetof(identification_t, destroy));
permitted->destroy_offset(permitted, offsetof(identification_t, destroy));
excluded->destroy_offset(excluded, offsetof(identification_t, destroy));
privkey->destroy(privkey);
pubkey->destroy(pubkey);
return cert;
}
/**
* Issue a certificate with single values
*/
static certificate_t* create_cert(certificate_t *ca, char *subject, char *san,
x509_flag_t flags, identification_t *permitted,
identification_t *excluded)
{
linked_list_t *plist, *elist, *sans;
identification_t *id;
plist = linked_list_create(); plist = linked_list_create();
if (permitted) if (permitted)
{ {
@@ -100,26 +133,7 @@ static certificate_t* create_cert(certificate_t *ca, char *subject, char *san,
id = identification_create_from_string(san); id = identification_create_from_string(san);
sans->insert_last(sans, id); sans->insert_last(sans, id);
} }
id = identification_create_from_string(subject); return create_cert_lists(ca, subject, sans, flags, plist, elist);
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
BUILD_SIGNING_KEY, privkey,
BUILD_PUBLIC_KEY, pubkey,
BUILD_SUBJECT, id,
BUILD_X509_FLAG, flags,
BUILD_SIGNING_CERT, ca,
BUILD_SUBJECT_ALTNAMES, sans,
BUILD_PERMITTED_NAME_CONSTRAINTS, plist,
BUILD_EXCLUDED_NAME_CONSTRAINTS, elist,
BUILD_END);
ck_assert(cert);
id->destroy(id);
sans->destroy_offset(sans, offsetof(identification_t, destroy));
plist->destroy_offset(plist, offsetof(identification_t, destroy));
elist->destroy_offset(elist, offsetof(identification_t, destroy));
privkey->destroy(privkey);
pubkey->destroy(pubkey);
return cert;
} }
/** /**
@@ -188,26 +202,29 @@ START_TEST(test_permitted_dn)
END_TEST END_TEST
static struct { static struct {
id_type_t ctype;
char *cdata; char *cdata;
char *subject; char *subject;
bool good; bool good;
} permitted_san[] = { } permitted_san[] = {
{ ID_FQDN, ".strongswan.org", "test.strongswan.org", TRUE }, { ".strongswan.org", "test.strongswan.org", TRUE },
{ ID_FQDN, "strongswan.org", "test.strongswan.org", TRUE }, { "strongswan.org", "test.strongswan.org", TRUE },
{ ID_FQDN, "a.b.c.strongswan.org", "d.a.b.c.strongswan.org", TRUE }, { "a.b.c.strongswan.org", "d.a.b.c.strongswan.org", TRUE },
{ ID_FQDN, "a.b.c.strongswan.org", "a.b.c.d.strongswan.org", FALSE }, { "a.b.c.strongswan.org", "a.b.c.d.strongswan.org", FALSE },
{ ID_FQDN, "strongswan.org", "strongswan.org.com", FALSE }, { "strongswan.org", "strongswan.org.com", FALSE },
{ ID_FQDN, ".strongswan.org", "strongswan.org", FALSE }, { ".strongswan.org", "strongswan.org", FALSE },
{ ID_FQDN, "strongswan.org", "nostrongswan.org", FALSE }, { "strongswan.org", "nostrongswan.org", FALSE },
{ ID_FQDN, "strongswan.org", "swan.org", FALSE }, { "strongswan.org", "swan.org", FALSE },
{ ID_FQDN, "strongswan.org", "swan.org", FALSE }, { "strongswan.org", "swan.org", FALSE },
{ ID_RFC822_ADDR, "[email protected]", "[email protected]", TRUE }, { "[email protected]", "[email protected]", TRUE },
{ ID_RFC822_ADDR, "[email protected]", "[email protected]", FALSE }, { "[email protected]", "[email protected]", FALSE },
{ ID_RFC822_ADDR, "strongswan.org", "[email protected]", TRUE }, { "email:strongswan.org", "[email protected]", TRUE },
{ ID_RFC822_ADDR, "strongswan.org", "[email protected]", FALSE }, { "email:strongswan.org", "[email protected]", FALSE },
{ ID_RFC822_ADDR, ".strongswan.org", "[email protected]", TRUE }, { "email:.strongswan.org", "[email protected]", TRUE },
{ ID_RFC822_ADDR, ".strongswan.org", "[email protected]", FALSE }, { "email:.strongswan.org", "[email protected]", FALSE },
{ "192.168.1.0/24", "192.168.1.10", TRUE },
{ "192.168.1.0/24", "192.168.2.10", FALSE },
{ "fec0::/64", "fec0::10", TRUE },
{ "fec0::/64", "fec1::10", FALSE },
}; };
START_TEST(test_permitted_san) START_TEST(test_permitted_san)
@@ -215,8 +232,7 @@ START_TEST(test_permitted_san)
certificate_t *ca, *sj; certificate_t *ca, *sj;
identification_t *id; identification_t *id;
id = identification_create_from_encoding(permitted_san[_i].ctype, id = identification_create_from_string(permitted_san[_i].cdata);
chunk_from_str(permitted_san[_i].cdata));
ca = create_cert(NULL, "CN=CA", NULL, X509_CA, id, NULL); ca = create_cert(NULL, "CN=CA", NULL, X509_CA, id, NULL);
sj = create_cert(ca, "CN=SJ", permitted_san[_i].subject, 0, NULL, NULL); sj = create_cert(ca, "CN=SJ", permitted_san[_i].subject, 0, NULL, NULL);
@@ -259,26 +275,29 @@ START_TEST(test_excluded_dn)
END_TEST END_TEST
static struct { static struct {
id_type_t ctype;
char *cdata; char *cdata;
char *subject; char *subject;
bool good; bool good;
} excluded_san[] = { } excluded_san[] = {
{ ID_FQDN, ".strongswan.org", "test.strongswan.org", FALSE }, { ".strongswan.org", "test.strongswan.org", FALSE },
{ ID_FQDN, "strongswan.org", "test.strongswan.org", FALSE }, { "strongswan.org", "test.strongswan.org", FALSE },
{ ID_FQDN, "a.b.c.strongswan.org", "d.a.b.c.strongswan.org", FALSE }, { "a.b.c.strongswan.org", "d.a.b.c.strongswan.org", FALSE },
{ ID_FQDN, "a.b.c.strongswan.org", "a.b.c.d.strongswan.org", TRUE }, { "a.b.c.strongswan.org", "a.b.c.d.strongswan.org", TRUE },
{ ID_FQDN, "strongswan.org", "strongswan.org.com", TRUE }, { "strongswan.org", "strongswan.org.com", TRUE },
{ ID_FQDN, ".strongswan.org", "strongswan.org", TRUE }, { ".strongswan.org", "strongswan.org", TRUE },
{ ID_FQDN, "strongswan.org", "nostrongswan.org", TRUE }, { "strongswan.org", "nostrongswan.org", TRUE },
{ ID_FQDN, "strongswan.org", "swan.org", TRUE }, { "strongswan.org", "swan.org", TRUE },
{ ID_FQDN, "strongswan.org", "swan.org", TRUE }, { "strongswan.org", "swan.org", TRUE },
{ ID_RFC822_ADDR, "[email protected]", "[email protected]", FALSE }, { "[email protected]", "[email protected]", FALSE },
{ ID_RFC822_ADDR, "[email protected]", "[email protected]", TRUE }, { "[email protected]", "[email protected]", TRUE },
{ ID_RFC822_ADDR, "strongswan.org", "[email protected]", FALSE }, { "email:strongswan.org", "[email protected]", FALSE },
{ ID_RFC822_ADDR, "strongswan.org", "[email protected]", TRUE }, { "email:strongswan.org", "[email protected]", TRUE },
{ ID_RFC822_ADDR, ".strongswan.org", "[email protected]", FALSE }, { "email:.strongswan.org", "[email protected]", FALSE },
{ ID_RFC822_ADDR, ".strongswan.org", "[email protected]", TRUE }, { "email:.strongswan.org", "[email protected]", TRUE },
{ "192.168.1.0/24", "192.168.1.10", FALSE },
{ "192.168.1.0/24", "192.168.2.10", TRUE },
{ "fec0::/64", "fec0::10", FALSE },
{ "fec0::/64", "fec1::10", TRUE },
}; };
START_TEST(test_excluded_san) START_TEST(test_excluded_san)
@@ -286,8 +305,7 @@ START_TEST(test_excluded_san)
certificate_t *ca, *sj; certificate_t *ca, *sj;
identification_t *id; identification_t *id;
id = identification_create_from_encoding(excluded_san[_i].ctype, id = identification_create_from_string(excluded_san[_i].cdata);
chunk_from_str(excluded_san[_i].cdata));
ca = create_cert(NULL, "CN=CA", NULL, X509_CA, NULL, id); ca = create_cert(NULL, "CN=CA", NULL, X509_CA, NULL, id);
sj = create_cert(ca, "CN=SJ", excluded_san[_i].subject, 0, NULL, NULL); sj = create_cert(ca, "CN=SJ", excluded_san[_i].subject, 0, NULL, NULL);
@@ -298,33 +316,45 @@ START_TEST(test_excluded_san)
} }
END_TEST END_TEST
/**
* Create an identity if the given string is not NULL
*/
static identification_t *create_test_id(char *id)
{
return id ? identification_create_from_string(id) : NULL;
}
static struct { static struct {
char *caconst; char *caconst;
char *imconst; char *imconst;
char *subject; char *subject;
bool good; bool good;
} permitted_dninh[] = { } permitted_dn_levels[] = {
{ "C=CH", "C=CH, O=strongSwan", "C=CH, O=strongSwan, CN=tester", TRUE }, { "C=CH", "C=CH, O=strongSwan", "C=CH, O=strongSwan, CN=tester", TRUE },
{ "C=CH", NULL, "C=CH, O=strongSwan, CN=tester", TRUE },
{ NULL, "C=CH, O=strongSwan", "C=CH, O=strongSwan, CN=tester", TRUE },
{ "C=CH", "C=DE, O=strongSwan", "C=CH, O=strongSwan, CN=tester", FALSE }, { "C=CH", "C=DE, O=strongSwan", "C=CH, O=strongSwan, CN=tester", FALSE },
{ "C=CH", "C=DE", "C=DE, O=strongSwan, CN=tester", FALSE },
{ "C=CH, O=strongSwan", "C=CH", "C=CH", FALSE }, { "C=CH, O=strongSwan", "C=CH", "C=CH", FALSE },
{ "C=CH, O=strongSwan, CN=Intermediate", NULL, "C=CH", FALSE },
}; };
START_TEST(test_permitted_dninh) START_TEST(test_permitted_dn_levels)
{ {
certificate_t *ca, *im, *sj; certificate_t *ca, *im, *sj;
identification_t *id; identification_t *id;
id = identification_create_from_string(permitted_dninh[_i].caconst); id = create_test_id(permitted_dn_levels[_i].caconst);
ca = create_cert(NULL, "C=CH, O=strongSwan, CN=CA", NULL, X509_CA, id, NULL); ca = create_cert(NULL, "C=CH, O=strongSwan, CN=CA", NULL, X509_CA, id, NULL);
id = identification_create_from_string(permitted_dninh[_i].imconst); id = create_test_id(permitted_dn_levels[_i].imconst);
im = create_cert(ca, "C=CH, O=strongSwan, CN=IM", NULL, X509_CA, id, NULL); im = create_cert(ca, "C=CH, O=strongSwan, CN=IM", NULL, X509_CA, id, NULL);
sj = create_cert(im, permitted_dninh[_i].subject, NULL, 0, NULL, NULL); sj = create_cert(im, permitted_dn_levels[_i].subject, NULL, 0, NULL, NULL);
creds->add_cert(creds, TRUE, ca); creds->add_cert(creds, TRUE, ca);
creds->add_cert(creds, FALSE, im); creds->add_cert(creds, FALSE, im);
creds->add_cert(creds, FALSE, sj); creds->add_cert(creds, FALSE, sj);
ck_assert(check_trust(sj->get_subject(sj)) == permitted_dninh[_i].good); ck_assert(check_trust(sj->get_subject(sj)) == permitted_dn_levels[_i].good);
} }
END_TEST END_TEST
@@ -333,28 +363,301 @@ static struct {
char *imconst; char *imconst;
char *subject; char *subject;
bool good; bool good;
} excluded_dninh[] = { } permitted_san_levels[] = {
{ "C=CH, O=strongSwan", "C=CH", "C=DE", TRUE }, { "strongswan.org", NULL, "strongswan.org", TRUE },
{ "C=CH, O=strongSwan", "C=DE", "C=CH", FALSE }, { "strongswan.org", NULL, "vpn.strongswan.org", TRUE },
{ "C=CH", "C=CH, O=strongSwan", "C=CH, O=strongSwan, CN=tester", FALSE }, { "strongswan.org", NULL, "strongswan.com", FALSE },
{ NULL, "strongswan.org", "strongswan.org", TRUE },
{ NULL, "strongswan.org", "strongswan.com", FALSE },
{ "strongswan.org", "strongswan.org", "strongswan.org", TRUE },
{ "strongswan.org", "strongswan.com", "strongswan.com", FALSE },
{ "strongswan.org", "vpn.strongswan.org", "strongswan.org", FALSE },
{ "strongswan.org", "vpn.strongswan.org", "vpn.strongswan.org", TRUE },
{ "strongswan.org", "vpn.strongswan.org", "a.vpn.strongswan.org", TRUE },
{ "strongswan.org", NULL, "[email protected]", TRUE },
{ "[email protected]", NULL, "[email protected]", TRUE },
{ "email:strongswan.org", NULL, "[email protected]", TRUE },
{ "email:strongswan.org", NULL, "[email protected]", FALSE },
{ "email:strongswan.org", "[email protected]", "[email protected]", TRUE },
{ "email:strongswan.org", "[email protected]", "[email protected]", FALSE },
{ "email:strongswan.org", "strongswan.org", "vpn.strongswan.org", TRUE },
{ "192.168.1.0/24", NULL, "192.168.1.10", TRUE },
{ "192.168.1.0/24", NULL, "192.168.2.10", FALSE },
{ "192.168.1.0/24", "192.168.2.0/24", "192.168.1.10", FALSE },
{ "192.168.1.0/24", "192.168.1.0/28", "192.168.1.10", TRUE },
{ "192.168.1.0/24", "192.168.1.16/28", "192.168.1.10", FALSE },
{ "fec0::/64", NULL, "fec0::10", TRUE },
{ "fec0::/64", NULL, "fec1::10", FALSE },
{ "fec0::/64", "fec1::/64", "fec1::10", FALSE },
{ "fec0::/64", "fec0::/123", "fec0::10", TRUE },
{ "fec0::/64", "fec0::20/123", "fec0::10", FALSE },
}; };
START_TEST(test_excluded_dninh) START_TEST(test_permitted_san_levels)
{ {
certificate_t *ca, *im, *sj; certificate_t *ca, *im, *sj;
identification_t *id; identification_t *id;
id = identification_create_from_string(excluded_dninh[_i].caconst); id = create_test_id(permitted_san_levels[_i].caconst);
ca = create_cert(NULL, "C=CH, O=strongSwan, CN=CA", NULL, X509_CA, NULL, id); ca = create_cert(NULL, "CN=CA", NULL, X509_CA, id, NULL);
id = identification_create_from_string(excluded_dninh[_i].imconst); id = create_test_id(permitted_san_levels[_i].imconst);
im = create_cert(ca, "C=DE, CN=IM", NULL, X509_CA, NULL, id); im = create_cert(ca, "CN=IM", NULL, X509_CA, id, NULL);
sj = create_cert(im, excluded_dninh[_i].subject, NULL, 0, NULL, NULL); sj = create_cert(im, "CN=EE", permitted_san_levels[_i].subject, 0, NULL, NULL);
creds->add_cert(creds, TRUE, ca); creds->add_cert(creds, TRUE, ca);
creds->add_cert(creds, FALSE, im); creds->add_cert(creds, FALSE, im);
creds->add_cert(creds, FALSE, sj); creds->add_cert(creds, FALSE, sj);
ck_assert(check_trust(sj->get_subject(sj)) == excluded_dninh[_i].good); ck_assert(check_trust(sj->get_subject(sj)) == permitted_san_levels[_i].good);
}
END_TEST
static struct {
char *caconst;
char *imconst;
char *subject;
bool good;
} excluded_dn_levels[] = {
{ "C=CH, O=strongSwan", "C=CH", "C=DE", TRUE },
{ "C=CH, O=strongSwan", "C=CH", "C=CH", FALSE },
{ "C=CH, O=strongSwan", "C=DE", "C=CH", TRUE },
{ "C=CH, O=strongSwan", "C=DE", "C=DE", FALSE },
{ "C=CH, O=strongSwan", "C=DE", "C=CH, O=strongSwan", FALSE },
{ NULL, "C=CH", "C=CH, O=strongSwan", FALSE },
{ "C=CH", NULL, "C=CH, O=strongSwan", FALSE },
{ "C=CH", "C=CH, O=strongSwan", "C=CH, O=strongSwan, CN=tester", FALSE },
{ "C=DE", NULL, "C=CH, O=strongSwan, CN=tester", FALSE },
};
START_TEST(test_excluded_dn_levels)
{
certificate_t *ca, *im, *sj;
identification_t *id;
id = create_test_id(excluded_dn_levels[_i].caconst);
ca = create_cert(NULL, "C=CH, O=strongSwan, CN=CA", NULL, X509_CA, NULL, id);
id = create_test_id(excluded_dn_levels[_i].imconst);
im = create_cert(ca, "C=DE, CN=IM", NULL, X509_CA, NULL, id);
sj = create_cert(im, excluded_dn_levels[_i].subject, NULL, 0, NULL, NULL);
creds->add_cert(creds, TRUE, ca);
creds->add_cert(creds, FALSE, im);
creds->add_cert(creds, FALSE, sj);
ck_assert(check_trust(sj->get_subject(sj)) == excluded_dn_levels[_i].good);
}
END_TEST
static struct {
char *caconst;
char *imconst;
char *subject;
bool good;
} excluded_san_levels[] = {
{ "strongswan.org", NULL, "strongswan.org", FALSE },
{ "strongswan.org", NULL, "strongswan.com", TRUE },
{ NULL, "strongswan.org", "strongswan.org", FALSE },
{ NULL, "strongswan.org", "strongswan.com", TRUE },
{ "strongswan.org", NULL, "test.strongswan.org", FALSE },
{ "test.strongswan.org", NULL, "test.strongswan.org", FALSE },
{ "test.strongswan.org", NULL, "strongswan.org", TRUE },
{ "test.strongswan.org", "strongswan.org", "strongswan.org", FALSE },
{ "test.strongswan.org", "strongswan.org", "test.strongswan.org", FALSE },
{ "test.strongswan.org", "test.strongswan.org", "test.strongswan.org", FALSE },
{ "strongswan.org", NULL, "[email protected]", TRUE },
{ "[email protected]", NULL, "[email protected]", FALSE },
{ "[email protected]", NULL, "[email protected]", TRUE },
{ "email:strongswan.org", NULL, "[email protected]", FALSE },
{ "email:strongswan.org", NULL, "[email protected]", TRUE },
{ "email:strongswan.org", "email:strongswan.com", "[email protected]", FALSE },
{ "email:strongswan.org", "email:strongswan.com", "[email protected]", FALSE },
{ "strongswan.org", "email:strongswan.com", "[email protected]", FALSE },
{ "192.168.1.0/24", NULL, "192.168.1.10", FALSE },
{ "192.168.1.0/24", NULL, "192.168.2.10", TRUE },
{ "192.168.1.0/24", "192.168.0.0/16", "192.168.2.10", FALSE },
{ "fec0::/64", NULL, "fec0::10", FALSE },
{ "fec0::/64", NULL, "fec1::10", TRUE },
{ "fec0::/64", "fec1::/12", "fec1::10", FALSE },
};
START_TEST(test_excluded_san_levels)
{
certificate_t *ca, *im, *sj;
identification_t *id;
id = create_test_id(excluded_san_levels[_i].caconst);
ca = create_cert(NULL, "CN=CA", NULL, X509_CA, NULL, id);
id = create_test_id(excluded_san_levels[_i].imconst);
im = create_cert(ca, "CN=IM", NULL, X509_CA, NULL, id);
sj = create_cert(im, "CN=EE", excluded_san_levels[_i].subject, 0, NULL, NULL);
creds->add_cert(creds, TRUE, ca);
creds->add_cert(creds, FALSE, im);
creds->add_cert(creds, FALSE, sj);
ck_assert(check_trust(sj->get_subject(sj)) == excluded_san_levels[_i].good);
}
END_TEST
/**
* Add an identity to the given list if not NULL
*/
static void add_identity_to_list(linked_list_t *list, char *idstr)
{
identification_t *id;
if (idstr)
{
id = identification_create_from_string(idstr);
list->insert_last(list, id);
}
}
/**
* Create a certificate with potentially multiple constraints/SANs
*/
static certificate_t *create_cert_multi(certificate_t *ca, char *subject,
x509_flag_t flags,
char *san1, char *san2,
char *pconst1, char *pconst2,
char *econst1, char *econst2)
{
linked_list_t *sans, *permitted, *excluded;
sans = linked_list_create();
add_identity_to_list(sans, san1);
add_identity_to_list(sans, san2);
permitted = linked_list_create();
add_identity_to_list(permitted, pconst1);
add_identity_to_list(permitted, pconst2);
excluded = linked_list_create();
add_identity_to_list(excluded, econst1);
add_identity_to_list(excluded, econst2);
return create_cert_lists(ca, subject, sans, flags, permitted, excluded);
}
static struct {
char *caconst1;
char *caconst2;
char *imconst1;
char *imconst2;
char *san1;
char *san2;
bool good;
} permitted_san_multi[] = {
{ "strongswan.org", "strongswan.com", NULL, NULL, "vpn.strongswan.org", NULL, TRUE },
{ "strongswan.org", "strongswan.com", NULL, NULL, "vpn.strongswan.com", NULL, TRUE },
{ "strongswan.org", "strongswan.com", NULL, NULL, "vpn.strongswan.org", "vpn.strongswan.com", TRUE },
{ NULL, NULL, "strongswan.org", "strongswan.com", "vpn.strongswan.org", NULL, TRUE },
{ NULL, NULL, "strongswan.org", "strongswan.com", "vpn.strongswan.com", NULL, TRUE },
{ NULL, NULL, "strongswan.org", "strongswan.com", "vpn.strongswan.org", "vpn.strongswan.com", TRUE },
{ "strongswan.org", "strongswan.com", "strongswan.org", NULL, "vpn.strongswan.org", NULL, TRUE },
{ "strongswan.org", "strongswan.com", "vpn.strongswan.org", NULL, "vpn.strongswan.org", NULL, TRUE },
{ "strongswan.org", "strongswan.com", "vpn.strongswan.org", NULL, "vpn.strongswan.org", NULL, TRUE },
{ "strongswan.org", "strongswan.com", "vpn.strongswan.org", NULL, "vpn.strongswan.org", "vpn.strongswan.com", FALSE },
{ "strongswan.org", "strongswan.com", "strongswan.com", NULL, "vpn.strongswan.org", "vpn.strongswan.com", FALSE },
{ "strongswan.org", "strongswan.com", "strongswan.org", NULL, "vpn.strongswan.com", NULL, FALSE },
{ "strongswan.org", "strongswan.com", "strongswan.com", NULL, "vpn.strongswan.org", NULL, FALSE },
{ "strongswan.org", "strongswan.com", "strongswan.com", NULL, "vpn.strongswan.com", NULL, TRUE },
{ "strongswan.org", "strongswan.com", "strongswan.net", NULL, "vpn.strongswan.com", NULL, FALSE },
{ "strongswan.org", "strongswan.com", "strongswan.net", NULL, "vpn.strongswan.org", NULL, FALSE },
{ "strongswan.org", "strongswan.com", "strongswan.net", NULL, "vpn.strongswan.net", NULL, FALSE },
{ "strongswan.org", "email:strongswan.org", NULL, NULL, "vpn.strongswan.org", NULL, TRUE },
{ "strongswan.org", "email:strongswan.org", NULL, NULL, "[email protected]", NULL, TRUE },
{ "strongswan.org", "email:strongswan.org", NULL, NULL, "vpn.strongswan.org", "[email protected]", TRUE },
{ "strongswan.org", "email:strongswan.org", "strongswan.org", NULL, "vpn.strongswan.org", NULL, TRUE },
{ "strongswan.org", "email:strongswan.org", "strongswan.org", NULL, "[email protected]", NULL, TRUE },
{ "strongswan.org", "email:strongswan.org", "strongswan.org", NULL, "vpn.strongswan.org", "[email protected]", TRUE },
{ "strongswan.org", "email:strongswan.org", "strongswan.org", "email:strongswan.com", "vpn.strongswan.org", NULL, TRUE },
{ "strongswan.org", "email:strongswan.org", "strongswan.org", "email:strongswan.com", "[email protected]", NULL, FALSE },
{ "strongswan.org", "email:strongswan.org", "strongswan.org", "email:strongswan.com", "vpn.strongswan.org", "[email protected]", FALSE },
{ "strongswan.org", "email:strongswan.org", "email:strongswan.org", NULL, "vpn.strongswan.org", NULL, TRUE },
{ "strongswan.org", "email:strongswan.org", "email:strongswan.org", NULL, "[email protected]", NULL, TRUE },
{ "strongswan.org", "email:strongswan.org", "email:strongswan.org", NULL, "vpn.strongswan.org", "[email protected]", TRUE },
{ "strongswan.org", "email:strongswan.org", "email:strongswan.org", "strongswan.com", "vpn.strongswan.org", NULL, FALSE },
{ "strongswan.org", "email:strongswan.org", "email:strongswan.org", "strongswan.com", "[email protected]", NULL, TRUE },
{ "strongswan.org", "email:strongswan.org", "email:strongswan.org", "strongswan.com", "vpn.strongswan.org", "[email protected]", FALSE },
};
START_TEST(test_permitted_san_multi)
{
certificate_t *ca, *im, *sj;
ca = create_cert_multi(NULL, "CN=CA", X509_CA, NULL, NULL,
permitted_san_multi[_i].caconst1,
permitted_san_multi[_i].caconst2, NULL, NULL);
im = create_cert_multi(ca, "CN=IM", X509_CA, NULL, NULL,
permitted_san_multi[_i].imconst1,
permitted_san_multi[_i].imconst2, NULL, NULL);
sj = create_cert_multi(im, "CN=EE", 0,
permitted_san_multi[_i].san1,
permitted_san_multi[_i].san2, NULL, NULL, NULL, NULL);
creds->add_cert(creds, TRUE, ca);
creds->add_cert(creds, FALSE, im);
creds->add_cert(creds, FALSE, sj);
ck_assert(check_trust(sj->get_subject(sj)) == permitted_san_multi[_i].good);
}
END_TEST
static struct {
char *caconst1;
char *caconst2;
char *imconst1;
char *imconst2;
char *san1;
char *san2;
bool good;
} excluded_san_multi[] = {
{ "strongswan.org", "strongswan.com", NULL, NULL, "vpn.strongswan.org", NULL, FALSE },
{ "strongswan.org", "strongswan.com", NULL, NULL, "[email protected]", NULL, TRUE },
{ "strongswan.org", "strongswan.com", NULL, NULL, "vpn.strongswan.com", NULL, FALSE },
{ "strongswan.org", "strongswan.com", NULL, NULL, "vpn.strongswan.net", NULL, TRUE },
{ "strongswan.org", "strongswan.com", NULL, NULL, "vpn.strongswan.org", "vpn.strongswan.com", FALSE },
{ "strongswan.org", "strongswan.com", NULL, NULL, "vpn.strongswan.org", "vpn.strongswan.net", FALSE },
{ "strongswan.org", NULL, NULL, NULL, "vpn.strongswan.org", "vpn.strongswan.com", FALSE },
{ "strongswan.org", NULL, NULL, NULL, "vpn.strongswan.com", "vpn.strongswan.org", FALSE },
{ NULL, NULL, "strongswan.org", "strongswan.com", "vpn.strongswan.org", NULL, FALSE },
{ NULL, NULL, "strongswan.org", "strongswan.com", "vpn.strongswan.com", NULL, FALSE },
{ NULL, NULL, "strongswan.org", "strongswan.com", "vpn.strongswan.net", NULL, TRUE },
{ NULL, NULL, "strongswan.org", "strongswan.com", "vpn.strongswan.org", "vpn.strongswan.com", FALSE },
{ "strongswan.org", "strongswan.com", "strongswan.net", NULL, "vpn.strongswan.net", NULL, FALSE },
{ "strongswan.net", NULL, "strongswan.org", "strongswan.com", "vpn.strongswan.net", NULL, FALSE },
{ "strongswan.net", NULL, "strongswan.org", "strongswan.com", "vpn.strongswan.org", NULL, FALSE },
{ "strongswan.net", NULL, "strongswan.org", "strongswan.com", "vpn.strongswan.com", NULL, FALSE },
{ "vpn.strongswan.org", "vpn.strongswan.com", "strongswan.org", NULL, "a.strongswan.org", NULL, FALSE },
{ "vpn.strongswan.org", "vpn.strongswan.com", "strongswan.org", NULL, "vpn.strongswan.com", NULL, FALSE },
{ "vpn.strongswan.org", "vpn.strongswan.com", "strongswan.org", NULL, "a.strongswan.com", NULL, TRUE },
{ "vpn.strongswan.org", "vpn.strongswan.com", "strongswan.org", "strongswan.com", "a.strongswan.com", NULL, FALSE },
{ "strongswan.org", "email:strongswan.org", NULL, NULL, "vpn.strongswan.org", NULL, FALSE },
{ "strongswan.org", "email:strongswan.org", NULL, NULL, "[email protected]", NULL, FALSE },
};
START_TEST(test_excluded_san_multi)
{
certificate_t *ca, *im, *sj;
ca = create_cert_multi(NULL, "CN=CA", X509_CA, NULL, NULL, NULL, NULL,
excluded_san_multi[_i].caconst1,
excluded_san_multi[_i].caconst2);
im = create_cert_multi(ca, "CN=IM", X509_CA, NULL, NULL, NULL, NULL,
excluded_san_multi[_i].imconst1,
excluded_san_multi[_i].imconst2);
sj = create_cert_multi(im, "CN=EE", 0,
excluded_san_multi[_i].san1,
excluded_san_multi[_i].san2, NULL, NULL, NULL, NULL);
creds->add_cert(creds, TRUE, ca);
creds->add_cert(creds, FALSE, im);
creds->add_cert(creds, FALSE, sj);
ck_assert(check_trust(sj->get_subject(sj)) == excluded_san_multi[_i].good);
} }
END_TEST END_TEST
@@ -385,14 +688,34 @@ Suite *certnames_suite_create()
tcase_add_loop_test(tc, test_excluded_san, 0, countof(excluded_san)); tcase_add_loop_test(tc, test_excluded_san, 0, countof(excluded_san));
suite_add_tcase(s, tc); suite_add_tcase(s, tc);
tc = tcase_create("permitted DN name constraint inherit"); tc = tcase_create("permitted DN name constraints multilevel");
tcase_add_checked_fixture(tc, setup, teardown); tcase_add_checked_fixture(tc, setup, teardown);
tcase_add_loop_test(tc, test_permitted_dninh, 0, countof(permitted_dninh)); tcase_add_loop_test(tc, test_permitted_dn_levels, 0, countof(permitted_dn_levels));
suite_add_tcase(s, tc); suite_add_tcase(s, tc);
tc = tcase_create("excluded DN name constraint inherit"); tc = tcase_create("permitted subjectAltName constraints multilevel");
tcase_add_checked_fixture(tc, setup, teardown); tcase_add_checked_fixture(tc, setup, teardown);
tcase_add_loop_test(tc, test_excluded_dninh, 0, countof(excluded_dninh)); tcase_add_loop_test(tc, test_permitted_san_levels, 0, countof(permitted_san_levels));
suite_add_tcase(s, tc);
tc = tcase_create("excluded DN name constraints multilevel");
tcase_add_checked_fixture(tc, setup, teardown);
tcase_add_loop_test(tc, test_excluded_dn_levels, 0, countof(excluded_dn_levels));
suite_add_tcase(s, tc);
tc = tcase_create("excluded subjectAltName constraints multilevel");
tcase_add_checked_fixture(tc, setup, teardown);
tcase_add_loop_test(tc, test_excluded_san_levels, 0, countof(excluded_san_levels));
suite_add_tcase(s, tc);
tc = tcase_create("permitted subjectAltName constraints multivalue");
tcase_add_checked_fixture(tc, setup, teardown);
tcase_add_loop_test(tc, test_permitted_san_multi, 0, countof(permitted_san_multi));
suite_add_tcase(s, tc);
tc = tcase_create("excluded subjectAltName constraints multivalue");
tcase_add_checked_fixture(tc, setup, teardown);
tcase_add_loop_test(tc, test_excluded_san_multi, 0, countof(excluded_san_multi));
suite_add_tcase(s, tc); suite_add_tcase(s, tc);
return s; return s;