From: Grigorii Demidov Date: Mon, 14 Mar 2016 11:12:21 +0000 (+0100) Subject: lib/dnssec: nsec, nsec3 (no-optout) referrals to unsigned subzones X-Git-Tag: v1.0.0~44 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f9ffeca9cc7382b8ed24217bfab1d0f34a51bd7a;p=thirdparty%2Fknot-resolver.git lib/dnssec: nsec, nsec3 (no-optout) referrals to unsigned subzones --- diff --git a/lib/dnssec/nsec.c b/lib/dnssec/nsec.c index 6f4af5332..7503cfa88 100644 --- a/lib/dnssec/nsec.c +++ b/lib/dnssec/nsec.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "lib/defines.h" #include "lib/dnssec/nsec.h" @@ -325,3 +326,66 @@ int kr_nsec_existence_denial(const knot_pkt_t *pkt, knot_section_t section_id, return kr_nsec_existence_denied(flags) ? kr_ok() : kr_error(ENOENT); } + +int kr_nsec_ref_to_unsigned(const knot_pkt_t *pkt) +{ + int nsec_found = 0; + uint8_t *bm = NULL; + uint16_t bm_size = 0; + const knot_pktsection_t *sec = knot_pkt_section(pkt, KNOT_AUTHORITY); + if (!sec) { + return kr_error(EINVAL); + } + for (unsigned i = 0; i < sec->count; ++i) { + const knot_rrset_t *ns = knot_pkt_rr(sec, i); + if (ns->type == KNOT_RRTYPE_DS) { + return kr_error(EEXIST); + } + if (ns->type != KNOT_RRTYPE_NS) { + continue; + } + nsec_found = 0; + for (unsigned j = 0; j < sec->count; ++j) { + const knot_rrset_t *nsec = knot_pkt_rr(sec, j); + if (nsec->type == KNOT_RRTYPE_DS) { + return kr_error(EEXIST); + } + if (nsec->type != KNOT_RRTYPE_NSEC) { + continue; + } + /* nsec found + * check if owner name matches the delegation name + */ + if (knot_dname_is_equal(nsec->owner, ns->owner)) { + /* nsec does not match the delegation */ + continue; + } + nsec_found = 1; + knot_nsec_bitmap(&nsec->rrs, &bm, &bm_size); + if (!bm) { + return kr_error(EINVAL); + } + if (kr_nsec_bitmap_contains_type(bm, bm_size, + KNOT_RRTYPE_NS) && + !kr_nsec_bitmap_contains_type(bm, bm_size, + KNOT_RRTYPE_DS) && + !kr_nsec_bitmap_contains_type(bm, bm_size, + KNOT_RRTYPE_SOA)) { + /* rfc4035, 5.2 */ + return kr_ok(); + } + } + if (nsec_found) { + /* nsec which owner matches + * the delegation name was found, + * but nsec type bitmap contains wrong types + */ + return kr_error(EINVAL); + } else { + /* nsec that matches delegation was not found */ + return kr_error(DNSSEC_NOT_FOUND); + } + } + + return kr_error(EINVAL); +} diff --git a/lib/dnssec/nsec.h b/lib/dnssec/nsec.h index 21ac6e4d3..c5dba139d 100644 --- a/lib/dnssec/nsec.h +++ b/lib/dnssec/nsec.h @@ -70,3 +70,15 @@ int kr_nsec_wildcard_answer_response_check(const knot_pkt_t *pkt, knot_section_t */ int kr_nsec_existence_denial(const knot_pkt_t *pkt, knot_section_t section_id, const knot_dname_t *sname, uint16_t stype); + +/** + * Referral to unsigned subzone check (RFC4035 5.2). + * @note No RRSIGs are validated. + * @param pkt Packet structure to be processed. + * @return 0 or error code: + * DNSSEC_NOT_FOUND - neither ds nor nsec records + * were not found. + * EEXIST - ds record was found. + * EINVAL - bogus. + */ +int kr_nsec_ref_to_unsigned(const knot_pkt_t *pkt); diff --git a/lib/dnssec/nsec3.c b/lib/dnssec/nsec3.c index 71a8949f9..c1a529fd5 100644 --- a/lib/dnssec/nsec3.c +++ b/lib/dnssec/nsec3.c @@ -703,3 +703,85 @@ int kr_nsec3_no_data(const knot_pkt_t *pkt, knot_section_t section_id, return ret; } +int kr_nsec3_ref_to_unsigned(const knot_pkt_t *pkt) +{ + int ret = kr_error(EINVAL); + int flags = 0; + uint8_t *bm = NULL; + uint16_t bm_size = 0; + const knot_pktsection_t *sec = knot_pkt_section(pkt, KNOT_AUTHORITY); + if (!sec) { + return kr_error(EINVAL); + } + for (unsigned i = 0; i < sec->count; ++i) { + const knot_rrset_t *ns = knot_pkt_rr(sec, i); + if (ns->type == KNOT_RRTYPE_DS) { + return kr_error(EEXIST); + } + if (ns->type != KNOT_RRTYPE_NS) { + continue; + } + flags = 0; + for (unsigned j = 0; j < sec->count; ++j) { + const knot_rrset_t *nsec3 = knot_pkt_rr(sec, j); + if (nsec3->type == KNOT_RRTYPE_DS) { + return kr_error(EEXIST); + } + if (nsec3->type != KNOT_RRTYPE_NSEC3) { + continue; + } + /* nsec3 found, check if owner name matches + * the delegation name + */ + ret = matches_name(&flags, nsec3, ns->owner); + if (ret != 0) { + return kr_error(EINVAL); + } + if (!(flags & FLG_NAME_MATCHED)) { + /* nsec3 owner name does not match + * the delegation name + */ + continue; + } + knot_nsec3_bitmap(&nsec3->rrs, 0, &bm, &bm_size); + if (!bm) { + return kr_error(EINVAL); + } + if (kr_nsec_bitmap_contains_type(bm, bm_size, + KNOT_RRTYPE_NS) && + !kr_nsec_bitmap_contains_type(bm, bm_size, + KNOT_RRTYPE_DS) && + !kr_nsec_bitmap_contains_type(bm, bm_size, + KNOT_RRTYPE_SOA)) { + /* Satisfies rfc5155, 8.9. paragraph 2 */ + return kr_ok(); + } + } + if (flags & FLG_NAME_MATCHED) { + /* nsec3 which owner matches + * the delegation name was found, + * but nsec3 type bitmap contains wrong types + */ + return kr_error(EINVAL); + } + /* nsec3 that matches the delegation was not found. + * Check rfc5155, 8.9. paragraph 4. + * Find closest provable encloser. + */ + const knot_dname_t *encloser_name = NULL; + const knot_rrset_t *covering_next_nsec3 = NULL; + ret = closest_encloser_proof(pkt, KNOT_AUTHORITY, ns->owner, &encloser_name, + NULL, &covering_next_nsec3); + if (ret != 0) { + return kr_error(EINVAL); + } + + if (has_optout(covering_next_nsec3)) { + return kr_error(DNSSEC_NOT_FOUND); + } else { + return kr_error(EINVAL); + } + } + return kr_error(EINVAL); +} + diff --git a/lib/dnssec/nsec3.h b/lib/dnssec/nsec3.h index 97f36d2a3..6ccdcf2e0 100644 --- a/lib/dnssec/nsec3.h +++ b/lib/dnssec/nsec3.h @@ -53,3 +53,15 @@ int kr_nsec3_wildcard_answer_response_check(const knot_pkt_t *pkt, knot_section_ */ int kr_nsec3_no_data(const knot_pkt_t *pkt, knot_section_t section_id, const knot_dname_t *sname, uint16_t stype); + +/** + * Referral to unsigned subzone check (RFC5155 8.9). + * @note No RRSIGs are validated. + * @param pkt Packet structure to be processed. + * @return 0 or error code: + * DNSSEC_NOT_FOUND - denial of existence can't be proven + * due to opt-out. + * EEXIST - ds record was found. + * EINVAL - bogus. + */ +int kr_nsec3_ref_to_unsigned(const knot_pkt_t *pkt); diff --git a/lib/layer/validate.c b/lib/layer/validate.c index 40ab2950c..e745ea226 100644 --- a/lib/layer/validate.c +++ b/lib/layer/validate.c @@ -277,7 +277,6 @@ static int update_delegation(struct kr_request *req, struct kr_query *qry, knot_ * If it contains neither, the referral is bogus (or an attempted downgrade attack). */ - /* Aggregate DS records (if using multiple keys) */ unsigned section = KNOT_ANSWER; if (!knot_wire_get_aa(answer->wire)) { /* Referral */ section = KNOT_AUTHORITY; @@ -287,17 +286,30 @@ static int update_delegation(struct kr_request *req, struct kr_query *qry, knot_ return kr_ok(); } - /* No DS provided, check for proof of non-existence. */ int ret = 0; const knot_dname_t *proved_name = knot_pkt_qname(answer); + /* Aggregate DS records (if using multiple keys) */ knot_rrset_t *new_ds = update_ds(cut, knot_pkt_section(answer, section)); if (!new_ds) { + /* No DS provided, check for proof of non-existence. */ if (!has_nsec3) { - ret = kr_nsec_existence_denial(answer, KNOT_AUTHORITY, proved_name, KNOT_RRTYPE_DS); + if (!knot_wire_get_aa(answer->wire)) { + /* Referral, check if it is referral to unsigned, rfc4035 5.2 */ + ret = kr_nsec_ref_to_unsigned(answer); + } else { + /* No-data answer */ + ret = kr_nsec_existence_denial(answer, KNOT_AUTHORITY, proved_name, KNOT_RRTYPE_DS); + } } else { - ret = kr_nsec3_no_data(answer, KNOT_AUTHORITY, proved_name, KNOT_RRTYPE_DS); + if (!knot_wire_get_aa(answer->wire)) { + /* Referral, check if it is referral to unsigned, rfc5155 8.9 */ + ret = kr_nsec3_ref_to_unsigned(answer); + } else { + /* No-data answer, QTYPE is DS, rfc5155 8.6 */ + ret = kr_nsec3_no_data(answer, KNOT_AUTHORITY, proved_name, KNOT_RRTYPE_DS); + } if (ret == kr_error(DNSSEC_NOT_FOUND)) { - /* Not bogus, but going insecure */ + /* Not bogus, going insecure due to optout */ ret = 0; } } diff --git a/tests/deckard b/tests/deckard index e73a08545..8b1a6c687 160000 --- a/tests/deckard +++ b/tests/deckard @@ -1 +1 @@ -Subproject commit e73a0854552d94e8bc5306e75c3a2229bc739531 +Subproject commit 8b1a6c6873067d78e88adda48d381142aa107bd4