mirror of
https://github.com/strongswan/strongswan.git
synced 2025-10-03 00:00:24 -04:00
Merge branch 'name-constraints'
This refactors the name constraints validation in the revocation plugin so it aligns with what's specified in RFC 5820. It also expands the subnet/range matching for identities. Closes strongswan/strongswan#2114
This commit is contained in:
commit
ddd926b698
@ -1553,7 +1553,7 @@ ADD_PLUGIN([random], [s charon pki scripts manager medsrv attest n
|
||||
ADD_PLUGIN([nonce], [s charon nm cmd aikgen])
|
||||
ADD_PLUGIN([x509], [s charon pki scripts attest nm cmd aikgen fuzz])
|
||||
ADD_PLUGIN([revocation], [s charon pki nm cmd])
|
||||
ADD_PLUGIN([constraints], [s charon nm cmd])
|
||||
ADD_PLUGIN([constraints], [s charon pki nm cmd])
|
||||
ADD_PLUGIN([acert], [s charon])
|
||||
ADD_PLUGIN([pubkey], [s charon pki cmd aikgen])
|
||||
ADD_PLUGIN([pkcs1], [s charon pki scripts manager medsrv attest nm cmd aikgen fuzz])
|
||||
|
@ -1,4 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2024 Tobias Brunner
|
||||
* Copyright (C) 2010 Martin Willi
|
||||
*
|
||||
* Copyright (C) secunet Security Networks AG
|
||||
@ -18,6 +19,8 @@
|
||||
|
||||
#include <utils/debug.h>
|
||||
#include <asn1/asn1.h>
|
||||
#include <collections/array.h>
|
||||
#include <collections/hashtable.h>
|
||||
#include <collections/linked_list.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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (!diff.len)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
if (c.ptr[0] == '.')
|
||||
{ /* constraint is domain, suffix match */
|
||||
return TRUE;
|
||||
@ -144,41 +151,155 @@ 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:
|
||||
matching = fqdn_matches(a, b);
|
||||
break;
|
||||
case ID_RFC822_ADDR:
|
||||
matching = email_matches(a, b);
|
||||
break;
|
||||
case ID_DER_ASN1_DN:
|
||||
return constraint == id;
|
||||
matching = dn_matches(a, b);
|
||||
break;
|
||||
case ID_IPV4_ADDR_SUBNET:
|
||||
return id == ID_IPV4_ADDR;
|
||||
case ID_IPV6_ADDR_SUBNET:
|
||||
return id == ID_IPV6_ADDR;
|
||||
matching = b->matches(b, a);
|
||||
break;
|
||||
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,
|
||||
certificate_t *cert, bool permitted)
|
||||
static bool id_matches_constraints(certificate_t *cert, identification_t *id,
|
||||
array_t *constraints, bool permitted)
|
||||
{
|
||||
x509_t *x509 = (x509_t*)cert;
|
||||
enumerator_t *enumerator;
|
||||
identification_t *subject, *constraint;
|
||||
id_type_t type;
|
||||
bool matches = FALSE;
|
||||
|
||||
subject = cert->get_subject(cert);
|
||||
type = id->get_type(id);
|
||||
|
||||
enumerator = array_create_enumerator(constraints);
|
||||
while (enumerator->enumerate(enumerator, &constraint))
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ID_FQDN:
|
||||
matches = fqdn_matches(constraint, id);
|
||||
break;
|
||||
case ID_RFC822_ADDR:
|
||||
matches = email_matches(constraint, id);
|
||||
break;
|
||||
case ID_DER_ASN1_DN:
|
||||
matches = dn_matches(constraint, id);
|
||||
break;
|
||||
case ID_IPV4_ADDR:
|
||||
case ID_IPV6_ADDR:
|
||||
matches = id->matches(id, constraint);
|
||||
break;
|
||||
default:
|
||||
/* shouldn't happen */
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
type = constraint->get_type(constraint);
|
||||
if (type == ID_DER_ASN1_DN)
|
||||
constraints = types->get(types, (void*)(uintptr_t)ID_DER_ASN1_DN);
|
||||
if (constraints)
|
||||
{
|
||||
matches = dn_matches(constraint, cert->get_subject(cert));
|
||||
matches = id_matches_constraints(cert, cert->get_subject(cert),
|
||||
constraints, permitted);
|
||||
if (matches != permitted)
|
||||
{
|
||||
return matches;
|
||||
@ -188,34 +309,16 @@ static bool name_constraint_matches(identification_t *constraint,
|
||||
enumerator = x509->create_subjectAltName_enumerator(x509);
|
||||
while (enumerator->enumerate(enumerator, &id))
|
||||
{
|
||||
if (type_matches(type, id->get_type(id)))
|
||||
type = constraint_type_from_id(id->get_type(id));
|
||||
constraints = types->get(types, (void*)(uintptr_t)type);
|
||||
if (constraints)
|
||||
{
|
||||
switch (type)
|
||||
matches = id_matches_constraints(cert, id, constraints, permitted);
|
||||
if (matches != permitted)
|
||||
{
|
||||
case ID_FQDN:
|
||||
matches = fqdn_matches(constraint, id);
|
||||
break;
|
||||
case ID_RFC822_ADDR:
|
||||
matches = email_matches(constraint, id);
|
||||
break;
|
||||
case ID_DER_ASN1_DN:
|
||||
matches = dn_matches(constraint, id);
|
||||
break;
|
||||
case ID_IPV4_ADDR_SUBNET:
|
||||
case ID_IPV6_ADDR_SUBNET:
|
||||
matches = id->matches(id, constraint);
|
||||
break;
|
||||
default:
|
||||
DBG1(DBG_CFG, "%N NameConstraint matching not implemented",
|
||||
id_type_names, type);
|
||||
matches = FALSE;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (matches != permitted)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
@ -223,112 +326,297 @@ static bool name_constraint_matches(identification_t *constraint,
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
x509_t *x509, bool permitted)
|
||||
static bool name_constraints_match(x509_t *x509, hashtable_t *permitted,
|
||||
hashtable_t *excluded)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
identification_t *id, *a, *b;
|
||||
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 (permitted && !cert_matches_constraints(x509, permitted, TRUE))
|
||||
{
|
||||
if (id->get_type(id) == type)
|
||||
return FALSE;
|
||||
}
|
||||
if (excluded && cert_matches_constraints(x509, excluded, FALSE))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
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);
|
||||
|
||||
enumerator = x509->create_name_constraint_enumerator(x509, permitted);
|
||||
while (enumerator->enumerate(enumerator, &constraint))
|
||||
{
|
||||
type = constraint->get_type(constraint);
|
||||
switch (type)
|
||||
{
|
||||
if (permitted)
|
||||
{ /* permitted constraint can be narrowed */
|
||||
a = constraint;
|
||||
b = id;
|
||||
}
|
||||
else
|
||||
{ /* excluded constraint can be widened */
|
||||
a = id;
|
||||
b = constraint;
|
||||
}
|
||||
switch (type)
|
||||
{
|
||||
case ID_FQDN:
|
||||
inherited = fqdn_matches(a, b);
|
||||
break;
|
||||
case ID_RFC822_ADDR:
|
||||
inherited = email_matches(a, b);
|
||||
break;
|
||||
case ID_DER_ASN1_DN:
|
||||
inherited = dn_matches(a, b);
|
||||
break;
|
||||
default:
|
||||
DBG1(DBG_CFG, "%N NameConstraint matching not implemented",
|
||||
id_type_names, type);
|
||||
inherited = FALSE;
|
||||
break;
|
||||
}
|
||||
case ID_FQDN:
|
||||
case ID_RFC822_ADDR:
|
||||
case ID_DER_ASN1_DN:
|
||||
case ID_IPV4_ADDR_SUBNET:
|
||||
case ID_IPV6_ADDR_SUBNET:
|
||||
break;
|
||||
default:
|
||||
DBG1(DBG_CFG, "%N NameConstraint not supported",
|
||||
id_type_names, type);
|
||||
success = FALSE;
|
||||
break;
|
||||
}
|
||||
if (inherited)
|
||||
if (!success)
|
||||
{
|
||||
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);
|
||||
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
|
||||
*/
|
||||
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;
|
||||
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);
|
||||
while (enumerator->enumerate(enumerator, &constraint))
|
||||
subject = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
|
||||
if (!subject || subject->get_type(subject) != CERT_X509)
|
||||
{
|
||||
if (!name_constraint_matches(constraint, subject, 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)
|
||||
{
|
||||
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;
|
||||
chain->insert_first(chain, cert);
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
chain->insert_first(chain, issuer);
|
||||
|
||||
enumerator = issuer->create_name_constraint_enumerator(issuer, FALSE);
|
||||
while (enumerator->enumerate(enumerator, &constraint))
|
||||
enumerator = chain->create_enumerator(chain);
|
||||
while (enumerator->enumerate(enumerator, &x509))
|
||||
{
|
||||
if (name_constraint_matches(constraint, subject, FALSE))
|
||||
if ((len > 0 && !name_constraints_match(x509, permitted, excluded)) ||
|
||||
!update_name_constraints(x509, &permitted, TRUE) ||
|
||||
!update_name_constraints(x509, &excluded, 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;
|
||||
valid = FALSE;
|
||||
*violator = (certificate_t*)x509;
|
||||
break;
|
||||
}
|
||||
len++;
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
return TRUE;
|
||||
|
||||
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);
|
||||
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)
|
||||
{
|
||||
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))
|
||||
{
|
||||
lib->credmgr->call_hook(lib->credmgr,
|
||||
|
@ -68,15 +68,15 @@ static char keydata[] = {
|
||||
/**
|
||||
* Issue a certificate with permitted/excluded name constraints
|
||||
*/
|
||||
static certificate_t* create_cert(certificate_t *ca, char *subject, char *san,
|
||||
x509_flag_t flags, identification_t *permitted,
|
||||
identification_t *excluded)
|
||||
static certificate_t* create_cert_lists(certificate_t *ca, char *subject,
|
||||
linked_list_t *sans, x509_flag_t flags,
|
||||
linked_list_t *permitted,
|
||||
linked_list_t *excluded)
|
||||
{
|
||||
private_key_t *privkey;
|
||||
public_key_t *pubkey;
|
||||
certificate_t *cert;
|
||||
identification_t *id;
|
||||
linked_list_t *plist, *elist, *sans;
|
||||
|
||||
privkey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
|
||||
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);
|
||||
pubkey = privkey->get_public_key(privkey);
|
||||
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();
|
||||
if (permitted)
|
||||
{
|
||||
@ -100,26 +133,7 @@ static certificate_t* create_cert(certificate_t *ca, char *subject, char *san,
|
||||
id = identification_create_from_string(san);
|
||||
sans->insert_last(sans, id);
|
||||
}
|
||||
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, 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;
|
||||
return create_cert_lists(ca, subject, sans, flags, plist, elist);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -188,26 +202,29 @@ START_TEST(test_permitted_dn)
|
||||
END_TEST
|
||||
|
||||
static struct {
|
||||
id_type_t ctype;
|
||||
char *cdata;
|
||||
char *subject;
|
||||
bool good;
|
||||
} permitted_san[] = {
|
||||
{ ID_FQDN, ".strongswan.org", "test.strongswan.org", TRUE },
|
||||
{ ID_FQDN, "strongswan.org", "test.strongswan.org", TRUE },
|
||||
{ ID_FQDN, "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 },
|
||||
{ ID_FQDN, "strongswan.org", "strongswan.org.com", FALSE },
|
||||
{ ID_FQDN, ".strongswan.org", "strongswan.org", FALSE },
|
||||
{ ID_FQDN, "strongswan.org", "nostrongswan.org", FALSE },
|
||||
{ ID_FQDN, "strongswan.org", "swan.org", FALSE },
|
||||
{ ID_FQDN, "strongswan.org", "swan.org", FALSE },
|
||||
{ ID_RFC822_ADDR, "tester@strongswan.org", "tester@strongswan.org", TRUE },
|
||||
{ ID_RFC822_ADDR, "tester@strongswan.org", "atester@strongswan.org", FALSE },
|
||||
{ ID_RFC822_ADDR, "strongswan.org", "tester@strongswan.org", TRUE },
|
||||
{ ID_RFC822_ADDR, "strongswan.org", "tester@test.strongswan.org", FALSE },
|
||||
{ ID_RFC822_ADDR, ".strongswan.org", "tester@test.strongswan.org", TRUE },
|
||||
{ ID_RFC822_ADDR, ".strongswan.org", "tester@strongswan.org", FALSE },
|
||||
{ ".strongswan.org", "test.strongswan.org", TRUE },
|
||||
{ "strongswan.org", "test.strongswan.org", TRUE },
|
||||
{ "a.b.c.strongswan.org", "d.a.b.c.strongswan.org", TRUE },
|
||||
{ "a.b.c.strongswan.org", "a.b.c.d.strongswan.org", FALSE },
|
||||
{ "strongswan.org", "strongswan.org.com", FALSE },
|
||||
{ ".strongswan.org", "strongswan.org", FALSE },
|
||||
{ "strongswan.org", "nostrongswan.org", FALSE },
|
||||
{ "strongswan.org", "swan.org", FALSE },
|
||||
{ "strongswan.org", "swan.org", FALSE },
|
||||
{ "tester@strongswan.org", "tester@strongswan.org", TRUE },
|
||||
{ "tester@strongswan.org", "atester@strongswan.org", FALSE },
|
||||
{ "email:strongswan.org", "tester@strongswan.org", TRUE },
|
||||
{ "email:strongswan.org", "tester@test.strongswan.org", FALSE },
|
||||
{ "email:.strongswan.org", "tester@test.strongswan.org", TRUE },
|
||||
{ "email:.strongswan.org", "tester@strongswan.org", 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)
|
||||
@ -215,8 +232,7 @@ START_TEST(test_permitted_san)
|
||||
certificate_t *ca, *sj;
|
||||
identification_t *id;
|
||||
|
||||
id = identification_create_from_encoding(permitted_san[_i].ctype,
|
||||
chunk_from_str(permitted_san[_i].cdata));
|
||||
id = identification_create_from_string(permitted_san[_i].cdata);
|
||||
ca = create_cert(NULL, "CN=CA", NULL, X509_CA, id, 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
|
||||
|
||||
static struct {
|
||||
id_type_t ctype;
|
||||
char *cdata;
|
||||
char *subject;
|
||||
bool good;
|
||||
} excluded_san[] = {
|
||||
{ ID_FQDN, ".strongswan.org", "test.strongswan.org", FALSE },
|
||||
{ ID_FQDN, "strongswan.org", "test.strongswan.org", FALSE },
|
||||
{ ID_FQDN, "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 },
|
||||
{ ID_FQDN, "strongswan.org", "strongswan.org.com", TRUE },
|
||||
{ ID_FQDN, ".strongswan.org", "strongswan.org", TRUE },
|
||||
{ ID_FQDN, "strongswan.org", "nostrongswan.org", TRUE },
|
||||
{ ID_FQDN, "strongswan.org", "swan.org", TRUE },
|
||||
{ ID_FQDN, "strongswan.org", "swan.org", TRUE },
|
||||
{ ID_RFC822_ADDR, "tester@strongswan.org", "tester@strongswan.org", FALSE },
|
||||
{ ID_RFC822_ADDR, "tester@strongswan.org", "atester@strongswan.org", TRUE },
|
||||
{ ID_RFC822_ADDR, "strongswan.org", "tester@strongswan.org", FALSE },
|
||||
{ ID_RFC822_ADDR, "strongswan.org", "tester@test.strongswan.org", TRUE },
|
||||
{ ID_RFC822_ADDR, ".strongswan.org", "tester@test.strongswan.org", FALSE },
|
||||
{ ID_RFC822_ADDR, ".strongswan.org", "tester@strongswan.org", TRUE },
|
||||
{ ".strongswan.org", "test.strongswan.org", FALSE },
|
||||
{ "strongswan.org", "test.strongswan.org", FALSE },
|
||||
{ "a.b.c.strongswan.org", "d.a.b.c.strongswan.org", FALSE },
|
||||
{ "a.b.c.strongswan.org", "a.b.c.d.strongswan.org", TRUE },
|
||||
{ "strongswan.org", "strongswan.org.com", TRUE },
|
||||
{ ".strongswan.org", "strongswan.org", TRUE },
|
||||
{ "strongswan.org", "nostrongswan.org", TRUE },
|
||||
{ "strongswan.org", "swan.org", TRUE },
|
||||
{ "strongswan.org", "swan.org", TRUE },
|
||||
{ "tester@strongswan.org", "tester@strongswan.org", FALSE },
|
||||
{ "tester@strongswan.org", "atester@strongswan.org", TRUE },
|
||||
{ "email:strongswan.org", "tester@strongswan.org", FALSE },
|
||||
{ "email:strongswan.org", "tester@test.strongswan.org", TRUE },
|
||||
{ "email:.strongswan.org", "tester@test.strongswan.org", FALSE },
|
||||
{ "email:.strongswan.org", "tester@strongswan.org", 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)
|
||||
@ -286,8 +305,7 @@ START_TEST(test_excluded_san)
|
||||
certificate_t *ca, *sj;
|
||||
identification_t *id;
|
||||
|
||||
id = identification_create_from_encoding(excluded_san[_i].ctype,
|
||||
chunk_from_str(excluded_san[_i].cdata));
|
||||
id = identification_create_from_string(excluded_san[_i].cdata);
|
||||
ca = create_cert(NULL, "CN=CA", NULL, X509_CA, NULL, id);
|
||||
sj = create_cert(ca, "CN=SJ", excluded_san[_i].subject, 0, NULL, NULL);
|
||||
|
||||
@ -298,33 +316,45 @@ START_TEST(test_excluded_san)
|
||||
}
|
||||
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 {
|
||||
char *caconst;
|
||||
char *imconst;
|
||||
char *subject;
|
||||
bool good;
|
||||
} permitted_dninh[] = {
|
||||
} permitted_dn_levels[] = {
|
||||
{ "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", "C=DE, O=strongSwan, CN=tester", 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;
|
||||
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);
|
||||
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);
|
||||
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, FALSE, im);
|
||||
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
|
||||
|
||||
@ -333,28 +363,301 @@ static struct {
|
||||
char *imconst;
|
||||
char *subject;
|
||||
bool good;
|
||||
} excluded_dninh[] = {
|
||||
{ "C=CH, O=strongSwan", "C=CH", "C=DE", TRUE },
|
||||
{ "C=CH, O=strongSwan", "C=DE", "C=CH", FALSE },
|
||||
{ "C=CH", "C=CH, O=strongSwan", "C=CH, O=strongSwan, CN=tester", FALSE },
|
||||
} permitted_san_levels[] = {
|
||||
{ "strongswan.org", NULL, "strongswan.org", TRUE },
|
||||
{ "strongswan.org", NULL, "vpn.strongswan.org", TRUE },
|
||||
{ "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, "tester@strongswan.org", TRUE },
|
||||
{ "tester@strongswan.org", NULL, "tester@strongswan.org", TRUE },
|
||||
{ "email:strongswan.org", NULL, "tester@strongswan.org", TRUE },
|
||||
{ "email:strongswan.org", NULL, "tester@strongswan.com", FALSE },
|
||||
{ "email:strongswan.org", "tester@strongswan.org", "tester@strongswan.org", TRUE },
|
||||
{ "email:strongswan.org", "tester@strongswan.org", "alice@strongswan.org", 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;
|
||||
identification_t *id;
|
||||
|
||||
id = identification_create_from_string(excluded_dninh[_i].caconst);
|
||||
ca = create_cert(NULL, "C=CH, O=strongSwan, CN=CA", NULL, X509_CA, NULL, id);
|
||||
id = identification_create_from_string(excluded_dninh[_i].imconst);
|
||||
im = create_cert(ca, "C=DE, CN=IM", NULL, X509_CA, NULL, id);
|
||||
sj = create_cert(im, excluded_dninh[_i].subject, NULL, 0, NULL, NULL);
|
||||
id = create_test_id(permitted_san_levels[_i].caconst);
|
||||
ca = create_cert(NULL, "CN=CA", NULL, X509_CA, id, NULL);
|
||||
id = create_test_id(permitted_san_levels[_i].imconst);
|
||||
im = create_cert(ca, "CN=IM", NULL, X509_CA, id, 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, FALSE, im);
|
||||
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, "tester@strongswan.org", TRUE },
|
||||
{ "tester@strongswan.org", NULL, "tester@strongswan.org", FALSE },
|
||||
{ "tester@strongswan.org", NULL, "alice@strongswan.org", TRUE },
|
||||
{ "email:strongswan.org", NULL, "tester@strongswan.org", FALSE },
|
||||
{ "email:strongswan.org", NULL, "tester@strongswan.com", TRUE },
|
||||
{ "email:strongswan.org", "email:strongswan.com", "tester@strongswan.org", FALSE },
|
||||
{ "email:strongswan.org", "email:strongswan.com", "tester@strongswan.com", FALSE },
|
||||
{ "strongswan.org", "email:strongswan.com", "tester@strongswan.com", 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, "tester@strongswan.org", NULL, TRUE },
|
||||
{ "strongswan.org", "email:strongswan.org", NULL, NULL, "vpn.strongswan.org", "tester@strongswan.org", TRUE },
|
||||
{ "strongswan.org", "email:strongswan.org", "strongswan.org", NULL, "vpn.strongswan.org", NULL, TRUE },
|
||||
{ "strongswan.org", "email:strongswan.org", "strongswan.org", NULL, "tester@strongswan.org", NULL, TRUE },
|
||||
{ "strongswan.org", "email:strongswan.org", "strongswan.org", NULL, "vpn.strongswan.org", "tester@strongswan.org", 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", "tester@strongswan.org", NULL, FALSE },
|
||||
{ "strongswan.org", "email:strongswan.org", "strongswan.org", "email:strongswan.com", "vpn.strongswan.org", "tester@strongswan.org", FALSE },
|
||||
{ "strongswan.org", "email:strongswan.org", "email:strongswan.org", NULL, "vpn.strongswan.org", NULL, TRUE },
|
||||
{ "strongswan.org", "email:strongswan.org", "email:strongswan.org", NULL, "tester@strongswan.org", NULL, TRUE },
|
||||
{ "strongswan.org", "email:strongswan.org", "email:strongswan.org", NULL, "vpn.strongswan.org", "tester@strongswan.org", 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", "tester@strongswan.org", NULL, TRUE },
|
||||
{ "strongswan.org", "email:strongswan.org", "email:strongswan.org", "strongswan.com", "vpn.strongswan.org", "tester@strongswan.org", 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, "tester@strongswan.org", 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, "tester@strongswan.org", 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
|
||||
|
||||
@ -385,14 +688,34 @@ Suite *certnames_suite_create()
|
||||
tcase_add_loop_test(tc, test_excluded_san, 0, countof(excluded_san));
|
||||
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_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);
|
||||
|
||||
tc = tcase_create("excluded DN name constraint inherit");
|
||||
tc = tcase_create("permitted subjectAltName constraints multilevel");
|
||||
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);
|
||||
|
||||
return s;
|
||||
|
@ -786,7 +786,7 @@ START_TEST(test_matches_binary)
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_matches_range)
|
||||
START_TEST(test_matches_range_addr)
|
||||
{
|
||||
identification_t *a, *b;
|
||||
|
||||
@ -869,6 +869,242 @@ START_TEST(test_matches_range)
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_matches_range_subnet)
|
||||
{
|
||||
identification_t *a, *b;
|
||||
|
||||
/* IPv4 subnets */
|
||||
a = identification_create_from_string("192.168.1.0/24");
|
||||
ck_assert(a->get_type(a) == ID_IPV4_ADDR_SUBNET);
|
||||
ck_assert(id_matches(a, "%any", ID_MATCH_ANY));
|
||||
ck_assert(id_matches(a, "0.0.0.0/0", ID_MATCH_MAX_WILDCARDS));
|
||||
ck_assert(id_matches(a, "192.168.1.1", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "192.168.1.2", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "192.168.1.1/32", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "192.168.1.0/32", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "192.168.1.0/24", ID_MATCH_PERFECT));
|
||||
ck_assert(id_matches(a, "192.168.0.0/24", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "192.168.0.0/16", ID_MATCH_ONE_WILDCARD));
|
||||
ck_assert(id_matches(a, "192.168.1.1-192.168.1.1", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "192.168.1.0-192.168.1.255", ID_MATCH_PERFECT));
|
||||
ck_assert(id_matches(a, "192.168.0.0-192.168.255.255", ID_MATCH_ONE_WILDCARD));
|
||||
ck_assert(id_matches(a, "foo@bar", ID_MATCH_NONE));
|
||||
|
||||
/* Malformed IPv4 subnet and range encoding */
|
||||
b = identification_create_from_encoding(ID_IPV4_ADDR_SUBNET, chunk_empty);
|
||||
ck_assert(a->matches(a, b) == ID_MATCH_NONE);
|
||||
b->destroy(b);
|
||||
b = identification_create_from_encoding(ID_IPV4_ADDR_RANGE, chunk_empty);
|
||||
ck_assert(a->matches(a, b) == ID_MATCH_NONE);
|
||||
b->destroy(b);
|
||||
b = identification_create_from_encoding(ID_IPV4_ADDR_RANGE,
|
||||
chunk_from_chars(0xc0,0xa8,0x01,0x28,0xc0,0xa8,0x01,0x00));
|
||||
ck_assert(a->matches(a, b) == ID_MATCH_NONE);
|
||||
b->destroy(b);
|
||||
a->destroy(a);
|
||||
|
||||
a = identification_create_from_string("192.168.1.1/32");
|
||||
ck_assert(id_matches(a, "%any", ID_MATCH_ANY));
|
||||
ck_assert(id_matches(a, "0.0.0.0/0", ID_MATCH_MAX_WILDCARDS));
|
||||
ck_assert(id_matches(a, "192.168.1.1/32", ID_MATCH_PERFECT));
|
||||
ck_assert(id_matches(a, "192.168.1.1/31", ID_MATCH_ONE_WILDCARD));
|
||||
ck_assert(id_matches(a, "192.168.1.1", ID_MATCH_PERFECT));
|
||||
ck_assert(id_matches(a, "192.168.1.2", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "192.168.1.0/24", ID_MATCH_ONE_WILDCARD));
|
||||
ck_assert(id_matches(a, "192.168.1.0-192.168.1.0", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "192.168.1.1-192.168.1.1", ID_MATCH_PERFECT));
|
||||
ck_assert(id_matches(a, "192.168.1.0-192.168.1.1", ID_MATCH_ONE_WILDCARD));
|
||||
ck_assert(id_matches(a, "192.168.1.1-192.168.1.2", ID_MATCH_ONE_WILDCARD));
|
||||
ck_assert(id_matches(a, "192.168.0.0-192.168.1.255", ID_MATCH_ONE_WILDCARD));
|
||||
a->destroy(a);
|
||||
|
||||
/* IPv6 subnets */
|
||||
a = identification_create_from_string("fec0::0/64");
|
||||
ck_assert(a->get_type(a) == ID_IPV6_ADDR_SUBNET);
|
||||
ck_assert(id_matches(a, "%any", ID_MATCH_ANY));
|
||||
ck_assert(id_matches(a, "::/0", ID_MATCH_MAX_WILDCARDS));
|
||||
ck_assert(id_matches(a, "fec0::1", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "fec0::2", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "fec0::1/128", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "fec0::/128", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "fec0::/64", ID_MATCH_PERFECT));
|
||||
ck_assert(id_matches(a, "fec0::/48", ID_MATCH_ONE_WILDCARD));
|
||||
ck_assert(id_matches(a, "fec1::/48", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "fec0::-fec0::1", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "fec0::-fec0::ffff:ffff:ffff:ffff", ID_MATCH_PERFECT));
|
||||
ck_assert(id_matches(a, "fec0::-fec0::f:ffff:ffff:ffff:ffff", ID_MATCH_ONE_WILDCARD));
|
||||
ck_assert(id_matches(a, "fec0::4001-fec0::4ffe", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "feb0::1-fec0::0", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "foo@bar", ID_MATCH_NONE));
|
||||
|
||||
/* Malformed IPv6 subnet and range encoding */
|
||||
b = identification_create_from_encoding(ID_IPV6_ADDR_SUBNET, chunk_empty);
|
||||
ck_assert(a->matches(a, b) == ID_MATCH_NONE);
|
||||
b->destroy(b);
|
||||
b = identification_create_from_encoding(ID_IPV6_ADDR_RANGE, chunk_empty);
|
||||
ck_assert(a->matches(a, b) == ID_MATCH_NONE);
|
||||
b->destroy(b);
|
||||
b = identification_create_from_encoding(ID_IPV6_ADDR_RANGE,
|
||||
chunk_from_chars(0xfe,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x4f,0xff,
|
||||
0xfe,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01 ));
|
||||
ck_assert(a->matches(a, b) == ID_MATCH_NONE);
|
||||
b->destroy(b);
|
||||
a->destroy(a);
|
||||
|
||||
a = identification_create_from_string("fec0::1/128");
|
||||
ck_assert(a->get_type(a) == ID_IPV6_ADDR_SUBNET);
|
||||
ck_assert(id_matches(a, "%any", ID_MATCH_ANY));
|
||||
ck_assert(id_matches(a, "::/0", ID_MATCH_MAX_WILDCARDS));
|
||||
ck_assert(id_matches(a, "fec0::1", ID_MATCH_PERFECT));
|
||||
ck_assert(id_matches(a, "fec0::2", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "fec0::1/128", ID_MATCH_PERFECT));
|
||||
ck_assert(id_matches(a, "fec0::/128", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "fec0::/64", ID_MATCH_ONE_WILDCARD));
|
||||
ck_assert(id_matches(a, "fec1::/48", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "fec0::0-fec0::0", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "fec0::1-fec0::1", ID_MATCH_PERFECT));
|
||||
ck_assert(id_matches(a, "fec0::0-fec0::1", ID_MATCH_ONE_WILDCARD));
|
||||
ck_assert(id_matches(a, "fec0::1-fec0::2", ID_MATCH_ONE_WILDCARD));
|
||||
ck_assert(id_matches(a, "fec0::-fec0::ffff:ffff:ffff:ffff", ID_MATCH_ONE_WILDCARD));
|
||||
a->destroy(a);
|
||||
|
||||
/* Malformed IPv4 subnet encoding */
|
||||
a = identification_create_from_encoding(ID_IPV4_ADDR_SUBNET, chunk_empty);
|
||||
ck_assert(id_matches(a, "192.168.1.1", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "0.0.0.0/0", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "0.0.0.0-255.255.255.255", ID_MATCH_NONE));
|
||||
a->destroy(a);
|
||||
|
||||
/* Malformed IPv6 subnet encoding */
|
||||
a = identification_create_from_encoding(ID_IPV6_ADDR_SUBNET, chunk_empty);
|
||||
ck_assert(id_matches(a, "fec0::1", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "::/0", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "::-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", ID_MATCH_NONE));
|
||||
a->destroy(a);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_matches_range_range)
|
||||
{
|
||||
identification_t *a, *b;
|
||||
|
||||
/* IPv4 ranges */
|
||||
a = identification_create_from_string("192.168.1.0-192.168.1.255");
|
||||
ck_assert(a->get_type(a) == ID_IPV4_ADDR_RANGE);
|
||||
ck_assert(id_matches(a, "%any", ID_MATCH_ANY));
|
||||
ck_assert(id_matches(a, "0.0.0.0/0", ID_MATCH_MAX_WILDCARDS));
|
||||
ck_assert(id_matches(a, "192.168.1.1", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "192.168.1.1/32", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "192.168.1.0/24", ID_MATCH_PERFECT));
|
||||
ck_assert(id_matches(a, "192.168.0.0/24", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "192.168.0.0/16", ID_MATCH_ONE_WILDCARD));
|
||||
ck_assert(id_matches(a, "192.168.1.1-192.168.1.1", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "192.168.1.0-192.168.1.255", ID_MATCH_PERFECT));
|
||||
ck_assert(id_matches(a, "192.168.0.0-192.168.255.255", ID_MATCH_ONE_WILDCARD));
|
||||
ck_assert(id_matches(a, "192.168.0.240-192.168.1.0", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "foo@bar", ID_MATCH_NONE));
|
||||
|
||||
/* Malformed IPv4 subnet and range encoding */
|
||||
b = identification_create_from_encoding(ID_IPV4_ADDR_SUBNET, chunk_empty);
|
||||
ck_assert(a->matches(a, b) == ID_MATCH_NONE);
|
||||
b->destroy(b);
|
||||
b = identification_create_from_encoding(ID_IPV4_ADDR_RANGE, chunk_empty);
|
||||
ck_assert(a->matches(a, b) == ID_MATCH_NONE);
|
||||
b->destroy(b);
|
||||
b = identification_create_from_encoding(ID_IPV4_ADDR_RANGE,
|
||||
chunk_from_chars(0xc0,0xa8,0x01,0x28,0xc0,0xa8,0x01,0x00));
|
||||
ck_assert(a->matches(a, b) == ID_MATCH_NONE);
|
||||
b->destroy(b);
|
||||
a->destroy(a);
|
||||
|
||||
a = identification_create_from_string("192.168.1.1-192.168.1.1");
|
||||
ck_assert(a->get_type(a) == ID_IPV4_ADDR_RANGE);
|
||||
ck_assert(id_matches(a, "%any", ID_MATCH_ANY));
|
||||
ck_assert(id_matches(a, "0.0.0.0/0", ID_MATCH_MAX_WILDCARDS));
|
||||
ck_assert(id_matches(a, "192.168.1.1", ID_MATCH_PERFECT));
|
||||
ck_assert(id_matches(a, "192.168.1.2", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "192.168.1.1/32", ID_MATCH_PERFECT));
|
||||
ck_assert(id_matches(a, "192.168.1.0/32", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "192.168.1.0/24", ID_MATCH_ONE_WILDCARD));
|
||||
ck_assert(id_matches(a, "192.168.0.0/24", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "192.168.1.1-192.168.1.1", ID_MATCH_PERFECT));
|
||||
ck_assert(id_matches(a, "192.168.1.0-192.168.1.0", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "192.168.1.1-192.168.1.1", ID_MATCH_PERFECT));
|
||||
ck_assert(id_matches(a, "192.168.1.0-192.168.1.1", ID_MATCH_ONE_WILDCARD));
|
||||
ck_assert(id_matches(a, "192.168.1.1-192.168.1.2", ID_MATCH_ONE_WILDCARD));
|
||||
ck_assert(id_matches(a, "192.168.0.0-192.168.1.255", ID_MATCH_ONE_WILDCARD));
|
||||
ck_assert(id_matches(a, "foo@bar", ID_MATCH_NONE));
|
||||
a->destroy(a);
|
||||
|
||||
/* IPv6 ranges */
|
||||
a = identification_create_from_string("fec0::-fec0::ffff:ffff:ffff:ffff");
|
||||
ck_assert(a->get_type(a) == ID_IPV6_ADDR_RANGE);
|
||||
ck_assert(id_matches(a, "%any", ID_MATCH_ANY));
|
||||
ck_assert(id_matches(a, "::/0", ID_MATCH_MAX_WILDCARDS));
|
||||
ck_assert(id_matches(a, "fec0::1", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "fec0::1/128", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "fec0::/128", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "fec0::/64", ID_MATCH_PERFECT));
|
||||
ck_assert(id_matches(a, "fec0::/48", ID_MATCH_ONE_WILDCARD));
|
||||
ck_assert(id_matches(a, "fec1::/48", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "fec0::-fec0::1", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "fec0::-fec0::ffff:ffff:ffff:ffff", ID_MATCH_PERFECT));
|
||||
ck_assert(id_matches(a, "fec0::-fec0::f:ffff:ffff:ffff:ffff", ID_MATCH_ONE_WILDCARD));
|
||||
ck_assert(id_matches(a, "fec0::4001-fec0::4ffe", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "feb0::1-fec0::0", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "foo@bar", ID_MATCH_NONE));
|
||||
|
||||
/* Malformed IPv6 subnet and range encoding */
|
||||
b = identification_create_from_encoding(ID_IPV6_ADDR_SUBNET, chunk_empty);
|
||||
ck_assert(a->matches(a, b) == ID_MATCH_NONE);
|
||||
b->destroy(b);
|
||||
b = identification_create_from_encoding(ID_IPV6_ADDR_RANGE, chunk_empty);
|
||||
ck_assert(a->matches(a, b) == ID_MATCH_NONE);
|
||||
b->destroy(b);
|
||||
b = identification_create_from_encoding(ID_IPV6_ADDR_RANGE,
|
||||
chunk_from_chars(0xfe,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x4f,0xff,
|
||||
0xfe,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01 ));
|
||||
ck_assert(a->matches(a, b) == ID_MATCH_NONE);
|
||||
b->destroy(b);
|
||||
a->destroy(a);
|
||||
|
||||
a = identification_create_from_string("fec0::1-fec0::1");
|
||||
ck_assert(a->get_type(a) == ID_IPV6_ADDR_RANGE);
|
||||
ck_assert(id_matches(a, "%any", ID_MATCH_ANY));
|
||||
ck_assert(id_matches(a, "::/0", ID_MATCH_MAX_WILDCARDS));
|
||||
ck_assert(id_matches(a, "fec0::1", ID_MATCH_PERFECT));
|
||||
ck_assert(id_matches(a, "fec0::2", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "fec0::1/128", ID_MATCH_PERFECT));
|
||||
ck_assert(id_matches(a, "fec0::/128", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "fec0::/64", ID_MATCH_ONE_WILDCARD));
|
||||
ck_assert(id_matches(a, "fec1::/48", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "fec0::0-fec0::0", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "fec0::1-fec0::1", ID_MATCH_PERFECT));
|
||||
ck_assert(id_matches(a, "fec0::0-fec0::1", ID_MATCH_ONE_WILDCARD));
|
||||
ck_assert(id_matches(a, "fec0::1-fec0::2", ID_MATCH_ONE_WILDCARD));
|
||||
ck_assert(id_matches(a, "fec0::-fec0::ffff:ffff:ffff:ffff", ID_MATCH_ONE_WILDCARD));
|
||||
a->destroy(a);
|
||||
|
||||
/* Malformed IPv4 range encoding */
|
||||
a = identification_create_from_encoding(ID_IPV4_ADDR_RANGE, chunk_empty);
|
||||
ck_assert(id_matches(a, "192.168.1.1", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "0.0.0.0/0", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "0.0.0.0-255.255.255.255", ID_MATCH_NONE));
|
||||
a->destroy(a);
|
||||
|
||||
/* Malformed IPv6 range encoding */
|
||||
a = identification_create_from_encoding(ID_IPV6_ADDR_RANGE, chunk_empty);
|
||||
ck_assert(id_matches(a, "fec0::1", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "::/0", ID_MATCH_NONE));
|
||||
ck_assert(id_matches(a, "::-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", ID_MATCH_NONE));
|
||||
a->destroy(a);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_matches_string)
|
||||
{
|
||||
identification_t *a;
|
||||
@ -1204,7 +1440,9 @@ Suite *identification_suite_create()
|
||||
tcase_add_loop_test(tc, test_matches_two_ou, 0, countof(rdn_matching));
|
||||
tcase_add_test(tc, test_matches_any);
|
||||
tcase_add_test(tc, test_matches_binary);
|
||||
tcase_add_test(tc, test_matches_range);
|
||||
tcase_add_test(tc, test_matches_range_addr);
|
||||
tcase_add_test(tc, test_matches_range_subnet);
|
||||
tcase_add_test(tc, test_matches_range_range);
|
||||
tcase_add_test(tc, test_matches_string);
|
||||
tcase_add_loop_test(tc, test_matches_empty, ID_ANY, ID_KEY_ID + 1);
|
||||
tcase_add_loop_test(tc, test_matches_empty_reverse, ID_ANY, ID_KEY_ID + 1);
|
||||
|
@ -1046,10 +1046,9 @@ METHOD(identification_t, matches_dn_relaxed, id_match_t,
|
||||
/**
|
||||
* Transform netmask to CIDR bits
|
||||
*/
|
||||
static int netmask_to_cidr(char *netmask, size_t address_size)
|
||||
static uint8_t netmask_to_cidr(char *netmask, uint8_t address_size)
|
||||
{
|
||||
uint8_t byte;
|
||||
int i, netbits = 0;
|
||||
uint8_t i, byte, netbits = 0;
|
||||
|
||||
for (i = 0; i < address_size; i++)
|
||||
{
|
||||
@ -1075,118 +1074,369 @@ static int netmask_to_cidr(char *netmask, size_t address_size)
|
||||
return netbits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given network/netmask to an address range
|
||||
*/
|
||||
static void subnet_to_range(chunk_t encoding, uint8_t address_size,
|
||||
uint8_t *from, uint8_t *to)
|
||||
{
|
||||
uint8_t *network, *netmask, netbits, mask, i;
|
||||
|
||||
network = encoding.ptr;
|
||||
netmask = encoding.ptr + address_size;
|
||||
netbits = netmask_to_cidr(netmask, address_size);
|
||||
|
||||
memcpy(from, network, address_size);
|
||||
memcpy(to, network, address_size);
|
||||
|
||||
i = netbits / 8;
|
||||
if (i < address_size)
|
||||
{
|
||||
mask = 0xff << (8 - netbits % 8);
|
||||
from[i] = from[i] & mask;
|
||||
to[i] = to[i] | ~mask;
|
||||
memset(&from[i+1], 0, address_size - i - 1);
|
||||
memset(&to[i+1], 0xff, address_size - i - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches one subnet (or address if netmask is NULL) against another
|
||||
*/
|
||||
static id_match_t match_subnets(uint8_t *network, uint8_t *netmask,
|
||||
uint8_t *other_network, uint8_t *other_netmask,
|
||||
uint8_t address_size)
|
||||
{
|
||||
uint8_t netbits, other_netbits, i;
|
||||
|
||||
other_netbits = other_netmask ? netmask_to_cidr(other_netmask, address_size)
|
||||
: 8 * address_size;
|
||||
if (!other_netbits)
|
||||
{
|
||||
return ID_MATCH_MAX_WILDCARDS;
|
||||
}
|
||||
|
||||
netbits = netmask ? netmask_to_cidr(netmask, address_size) : 8 * address_size;
|
||||
|
||||
if (netbits == other_netbits)
|
||||
{
|
||||
return memeq(network, other_network, address_size) ? ID_MATCH_PERFECT
|
||||
: ID_MATCH_NONE;
|
||||
}
|
||||
else if (netbits < other_netbits)
|
||||
{
|
||||
return ID_MATCH_NONE;
|
||||
}
|
||||
|
||||
for (i = 0; i < (other_netbits + 7)/8; i++)
|
||||
{
|
||||
if ((network[i] ^ other_network[i]) & other_netmask[i])
|
||||
{
|
||||
return ID_MATCH_NONE;
|
||||
}
|
||||
}
|
||||
return ID_MATCH_ONE_WILDCARD;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches two address ranges against each other
|
||||
*/
|
||||
static id_match_t match_ranges(uint8_t *from, uint8_t *to,
|
||||
uint8_t *other_from, uint8_t *other_to,
|
||||
uint8_t address_size)
|
||||
{
|
||||
const uint8_t zeroes[16] = { 0 };
|
||||
const uint8_t ones[16] = { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff };
|
||||
int match_from, match_to;
|
||||
|
||||
if (memcmp(to, from, address_size) < 0 ||
|
||||
memcmp(other_to, other_from, address_size) < 0)
|
||||
{
|
||||
/* to is smaller than from in one of the ranges */
|
||||
return ID_MATCH_NONE;
|
||||
}
|
||||
else if (memeq(other_from, zeroes, address_size) &&
|
||||
memeq(other_to, ones, address_size))
|
||||
{
|
||||
return ID_MATCH_MAX_WILDCARDS;
|
||||
}
|
||||
|
||||
match_from = memcmp(from, other_from, address_size);
|
||||
match_to = memcmp(to, other_to, address_size);
|
||||
|
||||
if (!match_from && !match_to)
|
||||
{
|
||||
return ID_MATCH_PERFECT;
|
||||
}
|
||||
else if (match_from >= 0 && match_to <= 0)
|
||||
{
|
||||
return ID_MATCH_ONE_WILDCARD;
|
||||
}
|
||||
return ID_MATCH_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Match a subnet to an address
|
||||
*/
|
||||
static id_match_t matches_subnet_to_addr(private_identification_t *this,
|
||||
identification_t *other,
|
||||
uint8_t address_size)
|
||||
{
|
||||
chunk_t other_encoding;
|
||||
uint8_t *network, *netmask, *address;
|
||||
|
||||
other_encoding = other->get_encoding(other);
|
||||
if (this->encoded.len != 2 * address_size ||
|
||||
other_encoding.len != address_size)
|
||||
{
|
||||
return ID_MATCH_NONE;
|
||||
}
|
||||
network = this->encoded.ptr;
|
||||
netmask = this->encoded.ptr + address_size;
|
||||
address = other_encoding.ptr;
|
||||
return match_subnets(network, netmask, address, NULL, address_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Match a subnet to an address
|
||||
*/
|
||||
static id_match_t matches_range_to_addr(private_identification_t *this,
|
||||
identification_t *other,
|
||||
uint8_t address_size)
|
||||
{
|
||||
chunk_t other_encoding;
|
||||
uint8_t *from, *to, *address;
|
||||
|
||||
other_encoding = other->get_encoding(other);
|
||||
if (this->encoded.len != 2 * address_size ||
|
||||
other_encoding.len != address_size)
|
||||
{
|
||||
return ID_MATCH_NONE;
|
||||
}
|
||||
from = this->encoded.ptr;
|
||||
to = this->encoded.ptr + address_size;
|
||||
address = other_encoding.ptr;
|
||||
return match_ranges(from, to, address, address, address_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches an address to a subnet
|
||||
*/
|
||||
static id_match_t matches_addr_to_subnet(private_identification_t *this,
|
||||
identification_t *other,
|
||||
uint8_t address_size)
|
||||
{
|
||||
chunk_t other_encoding;
|
||||
uint8_t *address, *network, *netmask;
|
||||
|
||||
other_encoding = other->get_encoding(other);
|
||||
if (this->encoded.len != address_size ||
|
||||
other_encoding.len != 2 * address_size)
|
||||
{
|
||||
return ID_MATCH_NONE;
|
||||
}
|
||||
address = this->encoded.ptr;
|
||||
network = other_encoding.ptr;
|
||||
netmask = other_encoding.ptr + address_size;
|
||||
return match_subnets(address, NULL, network, netmask, address_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a subnet to a subnet
|
||||
*/
|
||||
static id_match_t matches_subnet_to_subnet(private_identification_t *this,
|
||||
identification_t *other,
|
||||
uint8_t address_size)
|
||||
{
|
||||
chunk_t other_encoding;
|
||||
uint8_t *network, *netmask, *other_network, *other_netmask;
|
||||
|
||||
other_encoding = other->get_encoding(other);
|
||||
if (this->encoded.len != 2 * address_size ||
|
||||
other_encoding.len != 2 * address_size)
|
||||
{
|
||||
return ID_MATCH_NONE;
|
||||
}
|
||||
network = this->encoded.ptr;
|
||||
netmask = this->encoded.ptr + address_size;
|
||||
other_network = other_encoding.ptr;
|
||||
other_netmask = other_encoding.ptr + address_size;
|
||||
return match_subnets(network, netmask, other_network, other_netmask,
|
||||
address_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a range to a subnet
|
||||
*/
|
||||
static id_match_t matches_range_to_subnet(private_identification_t *this,
|
||||
identification_t *other,
|
||||
uint8_t address_size)
|
||||
{
|
||||
chunk_t other_encoding;
|
||||
uint8_t *from, *to, other_from[address_size], other_to[address_size];
|
||||
|
||||
other_encoding = other->get_encoding(other);
|
||||
if (this->encoded.len != 2 * address_size ||
|
||||
other_encoding.len != 2 * address_size)
|
||||
{
|
||||
return ID_MATCH_NONE;
|
||||
}
|
||||
|
||||
from = this->encoded.ptr;
|
||||
to = this->encoded.ptr + address_size;
|
||||
subnet_to_range(other_encoding, address_size, other_from, other_to);
|
||||
return match_ranges(from, to, other_from, other_to, address_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Match an address to a range
|
||||
*/
|
||||
static id_match_t matches_addr_to_range(private_identification_t *this,
|
||||
identification_t *other,
|
||||
uint8_t address_size)
|
||||
{
|
||||
chunk_t other_encoding;
|
||||
uint8_t *address, *from, *to;
|
||||
|
||||
other_encoding = other->get_encoding(other);
|
||||
if (this->encoded.len != address_size ||
|
||||
other_encoding.len != 2 * address_size)
|
||||
{
|
||||
return ID_MATCH_NONE;
|
||||
}
|
||||
address = this->encoded.ptr;
|
||||
from = other_encoding.ptr;
|
||||
to = other_encoding.ptr + address_size;
|
||||
return match_ranges(address, address, from, to, address_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Match a subnet to a range
|
||||
*/
|
||||
static id_match_t matches_subnet_to_range(private_identification_t *this,
|
||||
identification_t *other,
|
||||
uint8_t address_size)
|
||||
{
|
||||
chunk_t other_encoding;
|
||||
uint8_t from[address_size], to[address_size], *other_from, *other_to;
|
||||
|
||||
other_encoding = other->get_encoding(other);
|
||||
if (this->encoded.len != 2 * address_size ||
|
||||
other_encoding.len != 2 * address_size)
|
||||
{
|
||||
return ID_MATCH_NONE;
|
||||
}
|
||||
subnet_to_range(this->encoded, address_size, from, to);
|
||||
other_from = other_encoding.ptr;
|
||||
other_to = other_encoding.ptr + address_size;
|
||||
return match_ranges(from, to, other_from, other_to, address_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Match a range to a range
|
||||
*/
|
||||
static id_match_t matches_range_to_range(private_identification_t *this,
|
||||
identification_t *other,
|
||||
uint8_t address_size)
|
||||
{
|
||||
chunk_t other_encoding;
|
||||
uint8_t *from, *to, *other_from, *other_to;
|
||||
|
||||
other_encoding = other->get_encoding(other);
|
||||
if (this->encoded.len != 2 * address_size ||
|
||||
other_encoding.len != 2 * address_size)
|
||||
{
|
||||
return ID_MATCH_NONE;
|
||||
}
|
||||
from = this->encoded.ptr;
|
||||
to = this->encoded.ptr + address_size;
|
||||
other_from = other_encoding.ptr;
|
||||
other_to = other_encoding.ptr + address_size;
|
||||
return match_ranges(from, to, other_from, other_to, address_size);
|
||||
}
|
||||
|
||||
METHOD(identification_t, matches_range, id_match_t,
|
||||
private_identification_t *this, identification_t *other)
|
||||
{
|
||||
chunk_t other_encoding;
|
||||
uint8_t *address, *from, *to, *network, *netmask;
|
||||
size_t address_size = 0;
|
||||
int netbits, range_sign, i;
|
||||
id_type_t other_type;
|
||||
uint8_t address_size = 0;
|
||||
|
||||
if (other->get_type(other) == ID_ANY)
|
||||
other_type = other->get_type(other);
|
||||
if (other_type == ID_ANY)
|
||||
{
|
||||
return ID_MATCH_ANY;
|
||||
}
|
||||
if (this->type == other->get_type(other) &&
|
||||
if (this->type == other_type &&
|
||||
chunk_equals(this->encoded, other->get_encoding(other)))
|
||||
{
|
||||
return ID_MATCH_PERFECT;
|
||||
}
|
||||
if ((this->type == ID_IPV4_ADDR &&
|
||||
other->get_type(other) == ID_IPV4_ADDR_SUBNET))
|
||||
if (other_type == ID_IPV4_ADDR &&
|
||||
(this->type == ID_IPV4_ADDR_SUBNET || this->type == ID_IPV4_ADDR_RANGE))
|
||||
{
|
||||
address_size = sizeof(struct in_addr);
|
||||
}
|
||||
else if ((this->type == ID_IPV6_ADDR &&
|
||||
other->get_type(other) == ID_IPV6_ADDR_SUBNET))
|
||||
else if (other_type == ID_IPV6_ADDR &&
|
||||
(this->type == ID_IPV6_ADDR_SUBNET || this->type == ID_IPV6_ADDR_RANGE))
|
||||
{
|
||||
address_size = sizeof(struct in6_addr);
|
||||
}
|
||||
if (address_size)
|
||||
{
|
||||
other_encoding = other->get_encoding(other);
|
||||
if (this->encoded.len != address_size ||
|
||||
other_encoding.len != 2 * address_size)
|
||||
if (this->type == ID_IPV4_ADDR_SUBNET || this->type == ID_IPV6_ADDR_SUBNET)
|
||||
{
|
||||
return ID_MATCH_NONE;
|
||||
return matches_subnet_to_addr(this, other, address_size);
|
||||
}
|
||||
address = this->encoded.ptr;
|
||||
network = other_encoding.ptr;
|
||||
netmask = other_encoding.ptr + address_size;
|
||||
netbits = netmask_to_cidr(netmask, address_size);
|
||||
|
||||
if (netbits == 0)
|
||||
{
|
||||
return ID_MATCH_MAX_WILDCARDS;
|
||||
}
|
||||
if (netbits == 8 * address_size)
|
||||
{
|
||||
return memeq(address, network, address_size) ?
|
||||
ID_MATCH_PERFECT : ID_MATCH_NONE;
|
||||
}
|
||||
for (i = 0; i < (netbits + 7)/8; i++)
|
||||
{
|
||||
if ((address[i] ^ network[i]) & netmask[i])
|
||||
{
|
||||
return ID_MATCH_NONE;
|
||||
}
|
||||
}
|
||||
return ID_MATCH_ONE_WILDCARD;
|
||||
return matches_range_to_addr(this, other, address_size);
|
||||
}
|
||||
if ((this->type == ID_IPV4_ADDR &&
|
||||
other->get_type(other) == ID_IPV4_ADDR_RANGE))
|
||||
if (other_type == ID_IPV4_ADDR_SUBNET &&
|
||||
(this->type == ID_IPV4_ADDR || this->type == ID_IPV4_ADDR_SUBNET ||
|
||||
this->type == ID_IPV4_ADDR_RANGE))
|
||||
{
|
||||
address_size = sizeof(struct in_addr);
|
||||
}
|
||||
else if ((this->type == ID_IPV6_ADDR &&
|
||||
other->get_type(other) == ID_IPV6_ADDR_RANGE))
|
||||
else if (other_type == ID_IPV6_ADDR_SUBNET &&
|
||||
(this->type == ID_IPV6_ADDR || this->type == ID_IPV6_ADDR_SUBNET ||
|
||||
this->type == ID_IPV6_ADDR_RANGE))
|
||||
{
|
||||
address_size = sizeof(struct in6_addr);
|
||||
}
|
||||
if (address_size)
|
||||
{
|
||||
other_encoding = other->get_encoding(other);
|
||||
if (this->encoded.len != address_size ||
|
||||
other_encoding.len != 2 * address_size)
|
||||
if (this->type == ID_IPV4_ADDR || this->type == ID_IPV6_ADDR)
|
||||
{
|
||||
return ID_MATCH_NONE;
|
||||
return matches_addr_to_subnet(this, other, address_size);
|
||||
}
|
||||
address = this->encoded.ptr;
|
||||
from = other_encoding.ptr;
|
||||
to = other_encoding.ptr + address_size;
|
||||
|
||||
range_sign = memcmp(to, from, address_size);
|
||||
if (range_sign < 0)
|
||||
{ /* to is smaller than from */
|
||||
return ID_MATCH_NONE;
|
||||
}
|
||||
|
||||
/* check lower bound */
|
||||
for (i = 0; i < address_size; i++)
|
||||
else if (this->type == ID_IPV4_ADDR_SUBNET || this->type == ID_IPV6_ADDR_SUBNET)
|
||||
{
|
||||
if (address[i] != from[i])
|
||||
{
|
||||
if (address[i] < from[i])
|
||||
{
|
||||
return ID_MATCH_NONE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return matches_subnet_to_subnet(this, other, address_size);
|
||||
}
|
||||
|
||||
/* check upper bound */
|
||||
for (i = 0; i < address_size; i++)
|
||||
return matches_range_to_subnet(this, other, address_size);
|
||||
}
|
||||
if (other_type == ID_IPV4_ADDR_RANGE &&
|
||||
(this->type == ID_IPV4_ADDR || this->type == ID_IPV4_ADDR_SUBNET ||
|
||||
this->type == ID_IPV4_ADDR_RANGE))
|
||||
{
|
||||
address_size = sizeof(struct in_addr);
|
||||
}
|
||||
else if (other_type == ID_IPV6_ADDR_RANGE &&
|
||||
(this->type == ID_IPV6_ADDR || this->type == ID_IPV6_ADDR_SUBNET ||
|
||||
this->type == ID_IPV6_ADDR_RANGE))
|
||||
{
|
||||
address_size = sizeof(struct in6_addr);
|
||||
}
|
||||
if (address_size)
|
||||
{
|
||||
if (this->type == ID_IPV4_ADDR || this->type == ID_IPV6_ADDR)
|
||||
{
|
||||
if (address[i] != to[i])
|
||||
{
|
||||
if (address[i] > to[i])
|
||||
{
|
||||
return ID_MATCH_NONE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return matches_addr_to_range(this, other, address_size);
|
||||
}
|
||||
return range_sign ? ID_MATCH_ONE_WILDCARD : ID_MATCH_PERFECT;
|
||||
else if (this->type == ID_IPV4_ADDR_SUBNET || this->type == ID_IPV6_ADDR_SUBNET)
|
||||
{
|
||||
return matches_subnet_to_range(this, other, address_size);
|
||||
}
|
||||
return matches_range_to_range(this, other, address_size);
|
||||
}
|
||||
return ID_MATCH_NONE;
|
||||
}
|
||||
@ -1200,7 +1450,8 @@ int identification_printf_hook(printf_hook_data_t *data,
|
||||
private_identification_t *this = *((private_identification_t**)(args[0]));
|
||||
chunk_t proper;
|
||||
char buf[BUF_LEN], *pos;
|
||||
size_t len, address_size;
|
||||
uint8_t address_size;
|
||||
size_t len;
|
||||
int written;
|
||||
|
||||
if (this == NULL)
|
||||
@ -1402,6 +1653,10 @@ static private_identification_t *identification_create(id_type_t type)
|
||||
break;
|
||||
case ID_IPV4_ADDR:
|
||||
case ID_IPV6_ADDR:
|
||||
case ID_IPV4_ADDR_SUBNET:
|
||||
case ID_IPV6_ADDR_SUBNET:
|
||||
case ID_IPV4_ADDR_RANGE:
|
||||
case ID_IPV6_ADDR_RANGE:
|
||||
this->public.hash = _hash_binary;
|
||||
this->public.equals = _equals_binary;
|
||||
this->public.matches = _matches_range;
|
||||
|
Loading…
x
Reference in New Issue
Block a user