mirror of https://github.com/getdnsapi/getdns.git
NSEC handling complete
This commit is contained in:
parent
a66232153a
commit
4d4f235f76
116
src/dnssec.c
116
src/dnssec.c
|
@ -513,8 +513,7 @@ static int _getdns_verify_rrsig(
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/* This is a valid wildcard expansion. Calculate and return the
|
/* This is a valid wildcard expansion. Calculate and return the
|
||||||
* "Next closer" name, because we need another NSEC to cover it
|
* "Next closer" name, because we need another NSEC to cover it.
|
||||||
* for wildcards to hold...xi
|
|
||||||
* (except for rrsigs for NSECs, but those are dealt with later)
|
* (except for rrsigs for NSECs, but those are dealt with later)
|
||||||
*/
|
*/
|
||||||
to_skip = _dname_label_count(rrset->name)
|
to_skip = _dname_label_count(rrset->name)
|
||||||
|
@ -721,12 +720,12 @@ static int bitmap_has_type(priv_getdns_rdf_iter *bitmap, uint16_t rr_type)
|
||||||
|
|
||||||
static int nsec_bitmap_excludes_rrtype(getdns_rrset *nsec_rrset, uint16_t rr_type)
|
static int nsec_bitmap_excludes_rrtype(getdns_rrset *nsec_rrset, uint16_t rr_type)
|
||||||
{
|
{
|
||||||
rrtype_iter nsec_space, *nsec_rr;
|
rrtype_iter nsec_spc, *nsec_rr;
|
||||||
priv_getdns_rdf_iter bitmap_spc, *bitmap;
|
priv_getdns_rdf_iter bitmap_spc, *bitmap;
|
||||||
|
|
||||||
return (nsec_rrset->rr_type == GETDNS_RRTYPE_NSEC ||
|
return (nsec_rrset->rr_type == GETDNS_RRTYPE_NSEC ||
|
||||||
nsec_rrset->rr_type == GETDNS_RRTYPE_NSEC3 )
|
nsec_rrset->rr_type == GETDNS_RRTYPE_NSEC3 )
|
||||||
&& (nsec_rr = rrtype_iter_init(&nsec_space, nsec_rrset))
|
&& (nsec_rr = rrtype_iter_init(&nsec_spc, nsec_rrset))
|
||||||
&& (bitmap = priv_getdns_rdf_iter_init_at(&bitmap_spc, &nsec_rr->rr_i,
|
&& (bitmap = priv_getdns_rdf_iter_init_at(&bitmap_spc, &nsec_rr->rr_i,
|
||||||
nsec_rrset->rr_type == GETDNS_RRTYPE_NSEC ? 1: 5))
|
nsec_rrset->rr_type == GETDNS_RRTYPE_NSEC ? 1: 5))
|
||||||
&& !bitmap_has_type(bitmap, rr_type);
|
&& !bitmap_has_type(bitmap, rr_type);
|
||||||
|
@ -734,12 +733,12 @@ static int nsec_bitmap_excludes_rrtype(getdns_rrset *nsec_rrset, uint16_t rr_typ
|
||||||
|
|
||||||
static int nsec_bitmap_includes_rrtype(getdns_rrset *nsec_rrset, uint16_t rr_type)
|
static int nsec_bitmap_includes_rrtype(getdns_rrset *nsec_rrset, uint16_t rr_type)
|
||||||
{
|
{
|
||||||
rrtype_iter nsec_space, *nsec_rr;
|
rrtype_iter nsec_spc, *nsec_rr;
|
||||||
priv_getdns_rdf_iter bitmap_spc, *bitmap;
|
priv_getdns_rdf_iter bitmap_spc, *bitmap;
|
||||||
|
|
||||||
return (nsec_rrset->rr_type == GETDNS_RRTYPE_NSEC ||
|
return (nsec_rrset->rr_type == GETDNS_RRTYPE_NSEC ||
|
||||||
nsec_rrset->rr_type == GETDNS_RRTYPE_NSEC3 )
|
nsec_rrset->rr_type == GETDNS_RRTYPE_NSEC3 )
|
||||||
&& (nsec_rr = rrtype_iter_init(&nsec_space, nsec_rrset))
|
&& (nsec_rr = rrtype_iter_init(&nsec_spc, nsec_rrset))
|
||||||
&& (bitmap = priv_getdns_rdf_iter_init_at(&bitmap_spc, &nsec_rr->rr_i,
|
&& (bitmap = priv_getdns_rdf_iter_init_at(&bitmap_spc, &nsec_rr->rr_i,
|
||||||
nsec_rrset->rr_type == GETDNS_RRTYPE_NSEC ? 1: 5))
|
nsec_rrset->rr_type == GETDNS_RRTYPE_NSEC ? 1: 5))
|
||||||
&& bitmap_has_type(bitmap, rr_type);
|
&& bitmap_has_type(bitmap, rr_type);
|
||||||
|
@ -823,7 +822,8 @@ static int nsec_covers_name(
|
||||||
int nsec_cmp;
|
int nsec_cmp;
|
||||||
uint8_t *common1, *common2;
|
uint8_t *common1, *common2;
|
||||||
|
|
||||||
if ( !(rr = rrtype_iter_init(&rr_spc, nsec))
|
if (/* Get owner and next, nicely decompressed */
|
||||||
|
!(rr = rrtype_iter_init(&rr_spc, nsec))
|
||||||
|| !(rdf = priv_getdns_rdf_iter_init(&rdf_spc, &rr->rr_i))
|
|| !(rdf = priv_getdns_rdf_iter_init(&rdf_spc, &rr->rr_i))
|
||||||
|| !(owner = priv_getdns_owner_if_or_as_decompressed(
|
|| !(owner = priv_getdns_owner_if_or_as_decompressed(
|
||||||
&rr->rr_i, owner_spc, &owner_len))
|
&rr->rr_i, owner_spc, &owner_len))
|
||||||
|
@ -845,16 +845,24 @@ static int nsec_covers_name(
|
||||||
|
|
||||||
nsec_cmp = dname_compare(owner, next);
|
nsec_cmp = dname_compare(owner, next);
|
||||||
if (nsec_cmp < 0) {
|
if (nsec_cmp < 0) {
|
||||||
DEBUG_SEC("nsec owner < next\n");
|
/* Regular NSEC */
|
||||||
return dname_compare(name, owner) >= 0
|
return dname_compare(name, owner) >= 0
|
||||||
&& dname_compare(name, next) < 0;
|
&& dname_compare(name, next) < 0;
|
||||||
|
|
||||||
} else if (nsec_cmp > 0) {
|
} else if (nsec_cmp > 0) {
|
||||||
/* The wrap around nsec */
|
/* The wrap around nsec. So NSEC->nxt == zone.name.
|
||||||
DEBUG_SEC("nsec owner > next\n");
|
* qname must be a subdomain of that.
|
||||||
return dname_compare(name, owner) >= 0;
|
*/
|
||||||
|
return dname_compare(name, owner) >= 0
|
||||||
|
&& is_subdomain(next, name) && dname_compare(next, name);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
DEBUG_SEC("nsec owner == next\n");
|
/* This nsec is the only nsec.
|
||||||
return 1;
|
* zone.name NSEC zone.name, disproves everything else,
|
||||||
|
* but only for subdomains of that zone.
|
||||||
|
* (also no zone.name == qname of course)
|
||||||
|
*/
|
||||||
|
return is_subdomain(owner, name) && dname_compare(owner, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -979,6 +987,8 @@ static int find_nsec_covering_name(
|
||||||
{
|
{
|
||||||
rrset_iter i_spc, *i;
|
rrset_iter i_spc, *i;
|
||||||
getdns_rrset *n;
|
getdns_rrset *n;
|
||||||
|
rrtype_iter nsec_spc, *nsec_rr;
|
||||||
|
priv_getdns_rdf_iter bitmap_spc, *bitmap;
|
||||||
int keytag;
|
int keytag;
|
||||||
|
|
||||||
if (opt_out)
|
if (opt_out)
|
||||||
|
@ -998,6 +1008,38 @@ static int find_nsec_covering_name(
|
||||||
}
|
}
|
||||||
if ((n = rrset_iter_value(i))->rr_type == GETDNS_RRTYPE_NSEC
|
if ((n = rrset_iter_value(i))->rr_type == GETDNS_RRTYPE_NSEC
|
||||||
&& nsec_covers_name(n, name, NULL)
|
&& nsec_covers_name(n, name, NULL)
|
||||||
|
|
||||||
|
/* Get the bitmap rdata field */
|
||||||
|
&& (nsec_rr = rrtype_iter_init(&nsec_spc, n))
|
||||||
|
&& (bitmap = priv_getdns_rdf_iter_init_at(
|
||||||
|
&bitmap_spc, &nsec_rr->rr_i, 1))
|
||||||
|
|
||||||
|
/* NSEC should cover, but not match name...
|
||||||
|
* Unless it is wildcard match, but then we have to check
|
||||||
|
* that rrset->rr_type is not enlisted, because otherwise
|
||||||
|
* it should have matched the wildcard.
|
||||||
|
*
|
||||||
|
* Also no CNAME... cause that should have matched too.
|
||||||
|
*/
|
||||||
|
&& ( !priv_getdns_dname_equal(n->name, name)
|
||||||
|
|| ( name[0] == 1 && name[1] == (uint8_t)'*'
|
||||||
|
&& !bitmap_has_type(bitmap, rrset->rr_type)
|
||||||
|
&& !bitmap_has_type(bitmap, GETDNS_RRTYPE_CNAME)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
/* When qname is a subdomain of the NSEC owner, make
|
||||||
|
* sure there is no DNAME, and no delegation point
|
||||||
|
* there.
|
||||||
|
*/
|
||||||
|
&& ( !is_subdomain(n->name, name)
|
||||||
|
|| ( !bitmap_has_type(bitmap, GETDNS_RRTYPE_DNAME)
|
||||||
|
&& ( !bitmap_has_type(bitmap, GETDNS_RRTYPE_NS)
|
||||||
|
|| bitmap_has_type(bitmap, GETDNS_RRTYPE_SOA)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
&& (keytag = a_key_signed_rrset(dnskey, n))) {
|
&& (keytag = a_key_signed_rrset(dnskey, n))) {
|
||||||
|
|
||||||
debug_sec_print_rrset("NSEC: ", n);
|
debug_sec_print_rrset("NSEC: ", n);
|
||||||
|
@ -1045,7 +1087,7 @@ static int nsec3_find_next_closer(
|
||||||
static int key_proves_nonexistance(getdns_rrset *keyset, getdns_rrset *rrset)
|
static int key_proves_nonexistance(getdns_rrset *keyset, getdns_rrset *rrset)
|
||||||
{
|
{
|
||||||
getdns_rrset nsec_rrset, *cover, *ce;
|
getdns_rrset nsec_rrset, *cover, *ce;
|
||||||
rrtype_iter nsec_space, *nsec_rr;
|
rrtype_iter nsec_spc, *nsec_rr;
|
||||||
priv_getdns_rdf_iter bitmap_spc, *bitmap;
|
priv_getdns_rdf_iter bitmap_spc, *bitmap;
|
||||||
rrset_iter i_spc, *i;
|
rrset_iter i_spc, *i;
|
||||||
uint8_t *ce_name, *nc_name;
|
uint8_t *ce_name, *nc_name;
|
||||||
|
@ -1063,7 +1105,7 @@ static int key_proves_nonexistance(getdns_rrset *keyset, getdns_rrset *rrset)
|
||||||
nsec_rrset.rr_type = GETDNS_RRTYPE_NSEC;
|
nsec_rrset.rr_type = GETDNS_RRTYPE_NSEC;
|
||||||
|
|
||||||
if (/* A NSEC RR exists at the owner name of rrset */
|
if (/* A NSEC RR exists at the owner name of rrset */
|
||||||
(nsec_rr = rrtype_iter_init(&nsec_space, &nsec_rrset))
|
(nsec_rr = rrtype_iter_init(&nsec_spc, &nsec_rrset))
|
||||||
|
|
||||||
/* Get the bitmap rdata field */
|
/* Get the bitmap rdata field */
|
||||||
&& (bitmap = priv_getdns_rdf_iter_init_at(
|
&& (bitmap = priv_getdns_rdf_iter_init_at(
|
||||||
|
@ -1098,6 +1140,21 @@ static int key_proves_nonexistance(getdns_rrset *keyset, getdns_rrset *rrset)
|
||||||
debug_sec_print_rrset("NSEC NODATA proof for: ", rrset);
|
debug_sec_print_rrset("NSEC NODATA proof for: ", rrset);
|
||||||
return keytag;
|
return keytag;
|
||||||
}
|
}
|
||||||
|
/* More NSEC NODATA cases
|
||||||
|
* ======================
|
||||||
|
* There are a few NSEC NODATA cases where qname doesn't match
|
||||||
|
* NSEC->name:
|
||||||
|
*
|
||||||
|
* - An empty non terminal (ENT) will result in a NSEC covering the
|
||||||
|
* qname, where qname > NSEC->name and ce(qname) is a subdomain
|
||||||
|
* of NXT. This case is handled below after the covering NSEC is
|
||||||
|
* found.
|
||||||
|
*
|
||||||
|
* - Or a wildcard match without the type. The wildcard owner name
|
||||||
|
* match has special handing in the find_nsec_covering_name function.
|
||||||
|
* We still expect a NSEC covering the name though. For names with
|
||||||
|
* label < '*' there will thus be two NSECs. (is this true?)
|
||||||
|
*/
|
||||||
|
|
||||||
/* The NSEC Name error case
|
/* The NSEC Name error case
|
||||||
* ========================
|
* ========================
|
||||||
|
@ -1107,20 +1164,18 @@ static int key_proves_nonexistance(getdns_rrset *keyset, getdns_rrset *rrset)
|
||||||
; i ; i = rrset_iter_next(i)) {
|
; i ; i = rrset_iter_next(i)) {
|
||||||
|
|
||||||
cover = rrset_iter_value(i);
|
cover = rrset_iter_value(i);
|
||||||
/* Now let's find out if cover is indeed the NSEC covering
|
|
||||||
* rrset's owner name.
|
if (/* Is cover an NSEC rrset? */
|
||||||
*/
|
|
||||||
if (/* Is it an NSEC rrset? */
|
|
||||||
cover->rr_type != GETDNS_RRTYPE_NSEC
|
cover->rr_type != GETDNS_RRTYPE_NSEC
|
||||||
|
|
||||||
/* Does it cover the name */
|
/* Does it cover the name */
|
||||||
|| !nsec_covers_name(cover, rrset->name, &ce_name)
|
|| !nsec_covers_name(cover, rrset->name, &ce_name)
|
||||||
|
|
||||||
/* But not a match */
|
/* But not a match (because that would be NODATA case) */
|
||||||
|| priv_getdns_dname_equal(cover->name, rrset->name)
|
|| priv_getdns_dname_equal(cover->name, rrset->name)
|
||||||
|
|
||||||
/* Get the bitmap rdata field */
|
/* Get the bitmap rdata field */
|
||||||
|| !(nsec_rr = rrtype_iter_init(&nsec_space, cover))
|
|| !(nsec_rr = rrtype_iter_init(&nsec_spc, cover))
|
||||||
|| !(bitmap = priv_getdns_rdf_iter_init_at(
|
|| !(bitmap = priv_getdns_rdf_iter_init_at(
|
||||||
&bitmap_spc, &nsec_rr->rr_i, 1))
|
&bitmap_spc, &nsec_rr->rr_i, 1))
|
||||||
|
|
||||||
|
@ -1137,9 +1192,26 @@ static int key_proves_nonexistance(getdns_rrset *keyset, getdns_rrset *rrset)
|
||||||
)
|
)
|
||||||
|
|
||||||
/* And a valid signature please (as always) */
|
/* And a valid signature please (as always) */
|
||||||
|| !a_key_signed_rrset(keyset, cover))
|
|| !(keytag = a_key_signed_rrset(keyset, cover)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* We could have found a NSEC covering an Empty Non Terminal.
|
||||||
|
* In that case no NSEC covering the wildcard is needed.
|
||||||
|
* Because it was actually a NODATA proof.
|
||||||
|
*
|
||||||
|
* Empty NON terminals can be identified, by
|
||||||
|
* qname > NSEC->name && NSEC->nxt is subdomain of qname.
|
||||||
|
*
|
||||||
|
* nsec_covers_name() will set ce_name to qname when NSEC->nxt
|
||||||
|
* is a subdomain of qname.
|
||||||
|
*/
|
||||||
|
if ( dname_compare(rrset->name, cover->name) > 0
|
||||||
|
&& dname_compare(rrset->name, ce_name) == 0) {
|
||||||
|
|
||||||
|
debug_sec_print_dname("Empty Non Terminal: ", ce_name);
|
||||||
|
return keytag;
|
||||||
|
}
|
||||||
|
|
||||||
debug_sec_print_dname("Closest Encloser: ", ce_name);
|
debug_sec_print_dname("Closest Encloser: ", ce_name);
|
||||||
memcpy(wc_name + 2, ce_name, _dname_len(ce_name));
|
memcpy(wc_name + 2, ce_name, _dname_len(ce_name));
|
||||||
debug_sec_print_dname(" Wildcard: ", wc_name);
|
debug_sec_print_dname(" Wildcard: ", wc_name);
|
||||||
|
|
Loading…
Reference in New Issue