#include <libknot/rrset.h>
#include <libknot/rrtype/nsec.h>
#include <libknot/rrtype/rrsig.h>
+#include <dnssec/error.h>
#include "lib/defines.h"
#include "lib/dnssec/nsec.h"
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);
+}
*/
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);
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);
+}
+
*/
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);
* 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;
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;
}
}
-Subproject commit e73a0854552d94e8bc5306e75c3a2229bc739531
+Subproject commit 8b1a6c6873067d78e88adda48d381142aa107bd4