replaced {same,match}_dn() by compare_dn(), using the RDN enumerator

This commit is contained in:
Martin Willi 2009-07-06 11:46:26 +02:00
parent ed680e33c0
commit d692557298
1 changed files with 93 additions and 156 deletions

View File

@ -474,159 +474,6 @@ static bool dntoa(chunk_t dn, chunk_t *str)
return TRUE;
}
/**
* compare two distinguished names by
* comparing the individual RDNs
*/
static bool same_dn(chunk_t a, chunk_t b)
{
chunk_t rdn_a, rdn_b, attribute_a, attribute_b;
chunk_t oid_a, oid_b, value_a, value_b;
asn1_t type_a, type_b;
bool next_a, next_b;
/* same lengths for the DNs */
if (a.len != b.len)
{
return FALSE;
}
/* try a binary comparison first */
if (memeq(a.ptr, b.ptr, b.len))
{
return TRUE;
}
/* initialize DN parsing */
if (!init_rdn(a, &rdn_a, &attribute_a, &next_a) ||
!init_rdn(b, &rdn_b, &attribute_b, &next_b))
{
return FALSE;
}
/* fetch next RDN pair */
while (next_a && next_b)
{
/* parse next RDNs and check for errors */
if (!get_next_rdn(&rdn_a, &attribute_a, &oid_a, &value_a, &type_a, &next_a) ||
!get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b))
{
return FALSE;
}
/* OIDs must agree */
if (oid_a.len != oid_b.len || !memeq(oid_a.ptr, oid_b.ptr, oid_b.len))
{
return FALSE;
}
/* same lengths for values */
if (value_a.len != value_b.len)
{
return FALSE;
}
/* printableStrings and email RDNs require uppercase comparison */
if (type_a == type_b && (type_a == ASN1_PRINTABLESTRING ||
(type_a == ASN1_IA5STRING && asn1_known_oid(oid_a) == OID_PKCS9_EMAIL)))
{
if (strncasecmp(value_a.ptr, value_b.ptr, value_b.len) != 0)
{
return FALSE;
}
}
else
{
if (!strneq(value_a.ptr, value_b.ptr, value_b.len))
{
return FALSE;
}
}
}
/* both DNs must have same number of RDNs */
if (next_a || next_b)
{
return FALSE;
}
/* the two DNs are equal! */
return TRUE;
}
/**
* compare two distinguished names by comparing the individual RDNs.
* A single'*' character designates a wildcard RDN in DN b.
* TODO: Add support for different RDN order in DN !!
*/
bool match_dn(chunk_t a, chunk_t b, int *wildcards)
{
chunk_t rdn_a, rdn_b, attribute_a, attribute_b;
chunk_t oid_a, oid_b, value_a, value_b;
asn1_t type_a, type_b;
bool next_a, next_b;
/* initialize wildcard counter */
*wildcards = 0;
/* initialize DN parsing */
if (!init_rdn(a, &rdn_a, &attribute_a, &next_a) ||
!init_rdn(b, &rdn_b, &attribute_b, &next_b))
{
return FALSE;
}
/* fetch next RDN pair */
while (next_a && next_b)
{
/* parse next RDNs and check for errors */
if (!get_next_rdn(&rdn_a, &attribute_a, &oid_a, &value_a, &type_a, &next_a) ||
!get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b))
{
return FALSE;
}
/* OIDs must agree */
if (oid_a.len != oid_b.len || memcmp(oid_a.ptr, oid_b.ptr, oid_b.len) != 0)
{
return FALSE;
}
/* does rdn_b contain a wildcard? */
if (value_b.len == 1 && *value_b.ptr == '*')
{
(*wildcards)++;
continue;
}
/* same lengths for values */
if (value_a.len != value_b.len)
{
return FALSE;
}
/* printableStrings and email RDNs require uppercase comparison */
if (type_a == type_b && (type_a == ASN1_PRINTABLESTRING ||
(type_a == ASN1_IA5STRING && asn1_known_oid(oid_a) == OID_PKCS9_EMAIL)))
{
if (strncasecmp(value_a.ptr, value_b.ptr, value_b.len) != 0)
{
return FALSE;
}
}
else
{
if (!strneq(value_a.ptr, value_b.ptr, value_b.len))
{
return FALSE;
}
}
}
/* both DNs must have same number of RDNs */
if (next_a || next_b)
{
return FALSE;
}
/* the two DNs match! */
*wildcards = min(*wildcards, ID_MATCH_ONE_WILDCARD - ID_MATCH_MAX_WILDCARDS);
return TRUE;
}
/**
* Converts an LDAP-style human-readable ASCII-encoded
* ASN.1 distinguished name into binary DER-encoded format
@ -850,13 +697,102 @@ static bool equals_binary(private_identification_t *this, private_identification
return FALSE;
}
/**
* Compare to DNs, for equality if wc == NULL, for match otherwise
*/
static bool compare_dn(chunk_t t_dn, chunk_t o_dn, int *wc)
{
enumerator_t *t, *o;
chunk_t t_oid, o_oid, t_data, o_data;
u_char t_type, o_type;
bool t_next, o_next, finished = FALSE;
if (wc)
{
*wc = 0;
}
else
{
if (t_dn.len != o_dn.len)
{
return FALSE;
}
}
/* try a binary compare */
if (memeq(t_dn.ptr, o_dn.ptr, t_dn.len))
{
return TRUE;
}
t = create_rdn_enumerator(t_dn);
o = create_rdn_enumerator(o_dn);
while (TRUE)
{
t_next = t->enumerate(t, &t_oid, &t_type, &t_data);
o_next = o->enumerate(o, &o_oid, &o_type, &o_data);
if (!o_next && !t_next)
{
break;
}
finished = FALSE;
if (o_next != t_next)
{
break;
}
if (!chunk_equals(t_oid, o_oid))
{
break;
}
if (wc && o_data.len == 1 && o_data.ptr[0] == '*')
{
(*wc)++;
}
else
{
if (t_data.len != o_data.len)
{
break;
}
if (t_type == o_type &&
(t_type == ASN1_PRINTABLESTRING ||
(t_type == ASN1_IA5STRING &&
(asn1_known_oid(t_oid) == OID_PKCS9_EMAIL ||
asn1_known_oid(t_oid) == OID_EMAIL_ADDRESS))))
{ /* ignore case for printableStrings and email RDNs */
if (strncasecmp(t_data.ptr, o_data.ptr, t_data.len) != 0)
{
break;
}
}
else
{ /* respect case and length for everything else */
if (!memeq(t_data.ptr, o_data.ptr, t_data.len))
{
break;
}
}
}
/* the enumerator returns FALSE on parse error, we are finished
* if we have reached the end of the DN only */
if ((t_data.ptr + t_data.len == t_dn.ptr + t_dn.len) &&
(o_data.ptr + o_data.len == o_dn.ptr + o_dn.len))
{
finished = TRUE;
}
}
t->destroy(t);
o->destroy(o);
return finished;
}
/**
* Special implementation of identification_t.equals for ID_DER_ASN1_DN.
*/
static bool equals_dn(private_identification_t *this,
private_identification_t *other)
{
return same_dn(this->encoded, other->encoded);
return compare_dn(this->encoded, other->encoded, NULL);
}
/**
@ -960,7 +896,7 @@ static id_match_t matches_dn(private_identification_t *this,
private_identification_t *other)
{
int wc;
if (other->type == ID_ANY)
{
return ID_MATCH_ANY;
@ -968,8 +904,9 @@ static id_match_t matches_dn(private_identification_t *this,
if (this->type == other->type)
{
if (match_dn(this->encoded, other->encoded, &wc))
if (compare_dn(this->encoded, other->encoded, &wc))
{
wc = min(wc, ID_MATCH_ONE_WILDCARD - ID_MATCH_MAX_WILDCARDS);
return ID_MATCH_PERFECT - wc;
}
}